|
//
// KGModal.m
// KGModal
//
// Created by David Keegan on 10/5/12.
// Copyright (c) 2012 David Keegan. All rights reserved.
//
#import "KGModal.h"
#import <QuartzCore/QuartzCore.h>
CGFloat const kFadeInAnimationDuration = 0.3;
CGFloat const kTransformPart1AnimationDuration = 0.2;
CGFloat const kTransformPart2AnimationDuration = 0.1;
CGFloat const kDefaultCloseButtonPadding = 17.0;
NSString *const KGModalGradientViewTapped = @"KGModalGradientViewTapped";
NSString *const KGModalWillShowNotification = @"KGModalWillShowNotification";
NSString *const KGModalDidShowNotification = @"KGModalDidShowNotification";
NSString *const KGModalWillHideNotification = @"KGModalWillHideNotification";
NSString *const KGModalDidHideNotification = @"KGModalDidHideNotification";
@interface KGModalGradientView : UIView
@end
@interface KGModalContainerView : UIView
@property (weak, nonatomic) CALayer *styleLayer;
@property (strong, nonatomic) UIColor *modalBackgroundColor;
@end
@interface KGModalCloseButton : UIButton
@end
@interface KGModalViewController : UIViewController
@property (weak, nonatomic) KGModalGradientView *styleView;
@end
@interface KGModal()
@property (strong, nonatomic) TPWindow *window;
@property (strong, nonatomic) UIViewController *contentViewController;
@property (weak, nonatomic) KGModalViewController *viewController;
@property (weak, nonatomic) KGModalContainerView *containerView;
@property (weak, nonatomic) KGModalCloseButton *closeButton;
@property (weak, nonatomic) UIView *contentView;
@property (copy) void (^dismissHandler)();
@end
@implementation KGModal
@synthesize tapOutsideToDismiss = _tapOutsideToDismiss;
- (void)setTapOutsideToDismiss:(BOOL)tapOutside {
_tapOutsideToDismiss = tapOutside;
if (tapOutside) {
self.tapHandler = nil;
}
}
+ (instancetype)sharedInstance{
static id sharedInstance;
static dispatch_once_t once;
dispatch_once(&once, ^{
sharedInstance = [[[self class] alloc] init];
});
return sharedInstance;
}
- (instancetype)init{
if(!(self = [super init])){
return nil;
}
self.shouldRotate = YES;
self.tapOutsideToDismiss = YES;
self.animateWhenDismissed = YES;
self.closeButtonType = KGModalCloseButtonTypeLeft;
self.modalBackgroundColor = [UIColor colorWithWhite:0 alpha:0.5];
return self;
}
-(void)setCloseButtonType:(KGModalCloseButtonType)closeButtonType {
_closeButtonType = closeButtonType;
if(closeButtonType == KGModalCloseButtonTypeNone){
[self.closeButton setHidden:YES];
}else{
[self.closeButton setHidden:NO];
CGRect closeFrame = self.closeButton.frame;
if(closeButtonType == KGModalCloseButtonTypeRight){
closeFrame.origin.x = round(CGRectGetWidth(self.containerView.frame)-kDefaultCloseButtonPadding-CGRectGetWidth(closeFrame)/2);
}else{
closeFrame.origin.x = 0;
}
self.closeButton.frame = closeFrame;
}
}
- (void)showWithContentView:(UIView *)contentView completion:(void (^)(void))completion{
self.dismissHandler = nil;
self.tapHandler = nil;
[self showWithContentView:contentView andAnimated:YES completion:completion];
}
- (void)showWithContentViewController:(UIViewController *)contentViewController completion:(void (^)(void))completion{
self.dismissHandler = nil;
self.tapHandler = nil;
[self showWithContentViewController:contentViewController andAnimated:YES completion:completion];
}
- (void)showWithContentViewController:(UIViewController *)contentViewController andAnimated:(BOOL)animated completion:(void (^)(void))completion{
self.dismissHandler = nil;
self.contentViewController = contentViewController;
self.tapHandler = nil;
[self showWithContentView:contentViewController.view andAnimated:YES completion:(void (^)(void))completion];
}
- (void)showWithContentViewController:(UIViewController *)contentViewController andAnimated:(BOOL)animated completion:(void (^)(void))completion dismiss:(void (^)(void))dissmiss tapHandler:(void (^)(void))tapHandler{
self.dismissHandler = dissmiss;
self.contentViewController = contentViewController;
self.tapHandler = tapHandler;
[self showWithContentView:contentViewController.view andAnimated:YES completion:(void (^)(void))completion];
}
- (void)showWithContentView:(UIView *)contentView andAnimated:(BOOL)animated completion:(void (^)(void))completion{
self.window = [[TPWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight;
self.window.opaque = NO;
KGModalViewController *viewController = [[KGModalViewController alloc] init];
self.window.rootViewController = viewController;
self.viewController = viewController;
CGFloat padding = 17;
CGRect containerViewRect = CGRectInset(contentView.bounds, -padding, -padding);
containerViewRect.origin.x = containerViewRect.origin.y = 0;
containerViewRect.origin.x = round(CGRectGetMidX(self.window.bounds)-CGRectGetMidX(containerViewRect));
containerViewRect.origin.y = round(CGRectGetMidY(self.window.bounds)-CGRectGetMidY(containerViewRect));
KGModalContainerView *containerView = [[KGModalContainerView alloc] initWithFrame:containerViewRect];
containerView.modalBackgroundColor = self.modalBackgroundColor;
containerView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin|UIViewAutoresizingFlexibleRightMargin|
UIViewAutoresizingFlexibleTopMargin|UIViewAutoresizingFlexibleBottomMargin;
containerView.layer.rasterizationScale = [[UIScreen mainScreen] scale];
contentView.frame = (CGRect){padding, padding, contentView.bounds.size};
[containerView addSubview:contentView];
[viewController.view addSubview:containerView];
self.containerView = containerView;
KGModalCloseButton *closeButton = [[KGModalCloseButton alloc] init];
if(self.closeButtonType == KGModalCloseButtonTypeRight){
CGRect closeFrame = closeButton.frame;
closeFrame.origin.x = CGRectGetWidth(containerView.bounds)-CGRectGetWidth(closeFrame);
closeButton.frame = closeFrame;
}
[closeButton addTarget:self action:@selector(closeAction:) forControlEvents:UIControlEventTouchUpInside];
[containerView addSubview:closeButton];
self.closeButton = closeButton;
// Force adjust visibility and placing
[self setCloseButtonType:self.closeButtonType];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(tapCloseAction:)
name:KGModalGradientViewTapped object:nil];
// The window has to be un-hidden on the main thread
// This will cause the window to display
dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter] postNotificationName:KGModalWillShowNotification object:self];
[self.window makeKeyAndVisible];
if ([[TPUserDefault instance].isNightMode intValue] > 0) {
[self.window setMaskAfterOpenNightMode];
}
if(animated){
viewController.styleView.alpha = 0;
[UIView animateWithDuration:kFadeInAnimationDuration animations:^{
viewController.styleView.alpha = 1;
}];
containerView.alpha = 0;
containerView.layer.shouldRasterize = YES;
containerView.transform = CGAffineTransformScale(CGAffineTransformIdentity, 0.4, 0.4);
[UIView animateWithDuration:kTransformPart1AnimationDuration animations:^{
containerView.alpha = 1;
containerView.transform = CGAffineTransformScale(CGAffineTransformIdentity, 1, 1);
} completion:^(BOOL finished) {
containerView.layer.shouldRasterize = NO;
[[NSNotificationCenter defaultCenter] postNotificationName:KGModalDidShowNotification object:self];
if (completion) {
completion();
}
}];
}
});
}
- (void)closeAction:(id)sender{
[self hideAnimated:self.animateWhenDismissed];
}
- (void)tapCloseAction:(id)sender{
if(self.tapOutsideToDismiss){
[self hideAnimated:self.animateWhenDismissed];
}else {
if (self.tapHandler) {
self.tapHandler();
}
}
}
- (void)hide{
[self hideAnimated:YES];
}
- (void)hideWithCompletionBlock:(void(^)())completion{
[self hideAnimated:YES withCompletionBlock:completion];
}
- (void)hideAnimated:(BOOL)animated{
[self hideAnimated:animated withCompletionBlock:nil];
}
- (void)hideAnimated:(BOOL)animated withCompletionBlock:(void(^)())completion{
if (!self.window) {
if (completion) {
completion();
}
return;
}
if(!animated){
[self cleanup];
if (completion) {
completion();
}
[[NSNotificationCenter defaultCenter] postNotificationName:KGModalDidHideNotification object:self];
return;
}
dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter] postNotificationName:KGModalWillHideNotification object:self];
[UIView animateWithDuration:kFadeInAnimationDuration animations:^{
self.viewController.styleView.alpha = 0;
}];
self.containerView.layer.shouldRasterize = YES;
[UIView animateWithDuration:kTransformPart1AnimationDuration delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
self.containerView.alpha = 0;
self.containerView.transform = CGAffineTransformScale(CGAffineTransformIdentity, 0.4, 0.4);
} completion:^(BOOL finished2){
[self cleanup];
if (self.dismissHandler) {
self.dismissHandler();
}
if(completion){
completion();
}
[[NSNotificationCenter defaultCenter] postNotificationName:KGModalDidHideNotification object:self];
}];
});
}
- (void)cleanup{
[self.window setNoNightModeMask];
[[NSNotificationCenter defaultCenter] removeObserver:self];
[self.containerView removeFromSuperview];
[[[[UIApplication sharedApplication] delegate] window] makeKeyAndVisible];
[self.window removeFromSuperview];
self.contentViewController = nil;
self.window = nil;
}
- (void)setModalBackgroundColor:(UIColor *)modalBackgroundColor{
if(_modalBackgroundColor != modalBackgroundColor){
_modalBackgroundColor = modalBackgroundColor;
self.containerView.modalBackgroundColor = modalBackgroundColor;
}
}
- (void)dealloc{
[self cleanup];
}
@end
@implementation KGModalViewController
- (void)loadView{
self.view = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
}
- (void)viewDidLoad{
[super viewDidLoad];
self.view.backgroundColor = [UIColor clearColor];
self.view.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight;
KGModalGradientView *styleView = [[KGModalGradientView alloc] initWithFrame:self.view.bounds];
styleView.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight;
styleView.opaque = NO;
[self.view addSubview:styleView];
self.styleView = styleView;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation{
return [[KGModal sharedInstance] shouldRotate];
}
- (BOOL)shouldAutorotate{
return [[KGModal sharedInstance] shouldRotate];
}
@end
@implementation KGModalContainerView
- (instancetype)initWithFrame:(CGRect)frame{
if(!(self = [super initWithFrame:frame])){
return nil;
}
// CALayer *styleLayer = [[CALayer alloc] init];
// styleLayer.cornerRadius = 4;
// styleLayer.shadowColor= [[UIColor blackColor] CGColor];
// styleLayer.shadowOffset = CGSizeMake(0, 0);
// styleLayer.shadowOpacity = 0.5;
// styleLayer.borderWidth = 1;
// styleLayer.borderColor = [[UIColor whiteColor] CGColor];
// styleLayer.frame = CGRectInset(self.bounds, 12, 12);
// [self.layer addSublayer:styleLayer];
// self.styleLayer = styleLayer;
self.clipsToBounds = YES;
return self;
}
- (void)setModalBackgroundColor:(UIColor *)modalBackgroundColor{
if(_modalBackgroundColor != modalBackgroundColor){
_modalBackgroundColor = modalBackgroundColor;
self.styleLayer.backgroundColor = [modalBackgroundColor CGColor];
}
}
@end
@implementation KGModalGradientView
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
[[NSNotificationCenter defaultCenter] postNotificationName:KGModalGradientViewTapped object:nil];
}
- (void)drawRect:(CGRect)rect{
CGContextRef context = UIGraphicsGetCurrentContext();
if ([[TPUserDefault instance].isNightMode intValue] > 0) {
UIColor *maskColor = [UIColor colorWithWhite:0.25 alpha:0.55];
[maskColor set];
CGContextFillRect(context, self.bounds);
}else {
if([[KGModal sharedInstance] backgroundDisplayStyle] == KGModalBackgroundDisplayStyleSolid){
[[UIColor colorWithWhite:0 alpha:0.55] set];
CGContextFillRect(context, self.bounds);
}else{
CGContextSaveGState(context);
size_t gradLocationsNum = 2;
CGFloat gradLocations[2] = {0.0f, 1.0f};
CGFloat gradColors[8] = {0, 0, 0, 0.3, 0, 0, 0, 0.8};
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGGradientRef gradient = CGGradientCreateWithColorComponents(colorSpace, gradColors, gradLocations, gradLocationsNum);
CGColorSpaceRelease(colorSpace), colorSpace = NULL;
CGPoint gradCenter= CGPointMake(round(CGRectGetMidX(self.bounds)), round(CGRectGetMidY(self.bounds)));
CGFloat gradRadius = MAX(CGRectGetWidth(self.bounds), CGRectGetHeight(self.bounds));
CGContextDrawRadialGradient(context, gradient, gradCenter, 0, gradCenter, gradRadius, kCGGradientDrawsAfterEndLocation);
CGGradientRelease(gradient), gradient = NULL;
CGContextRestoreGState(context);
}
}
}
@end
@implementation KGModalCloseButton
- (instancetype)init{
if(!(self = [super initWithFrame:(CGRect){0, 0, 32, 32}])){
return nil;
}
static UIImage *closeButtonImage;
static dispatch_once_t once;
dispatch_once(&once, ^{
closeButtonImage = [self closeButtonImage];
});
[self setBackgroundImage:closeButtonImage forState:UIControlStateNormal];
return self;
}
- (UIImage *)closeButtonImage{
UIGraphicsBeginImageContextWithOptions(self.bounds.size, NO, 0);
//// General Declarations
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = UIGraphicsGetCurrentContext();
//// Color Declarations
UIColor *topGradient = [UIColor colorWithRed:0.21 green:0.21 blue:0.21 alpha:0.9];
UIColor *bottomGradient = [UIColor colorWithRed:0.03 green:0.03 blue:0.03 alpha:0.9];
//// Gradient Declarations
NSArray *gradientColors = @[(id)topGradient.CGColor,
(id)bottomGradient.CGColor];
CGFloat gradientLocations[] = {0, 1};
CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, (__bridge CFArrayRef)gradientColors, gradientLocations);
//// Shadow Declarations
CGColorRef shadow = [UIColor blackColor].CGColor;
CGSize shadowOffset = CGSizeMake(0, 1);
CGFloat shadowBlurRadius = 3;
CGColorRef shadow2 = [UIColor blackColor].CGColor;
CGSize shadow2Offset = CGSizeMake(0, 1);
CGFloat shadow2BlurRadius = 0;
//// Oval Drawing
UIBezierPath *ovalPath = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(4, 3, 24, 24)];
CGContextSaveGState(context);
[ovalPath addClip];
CGContextDrawLinearGradient(context, gradient, CGPointMake(16, 3), CGPointMake(16, 27), 0);
CGContextRestoreGState(context);
CGContextSaveGState(context);
CGContextSetShadowWithColor(context, shadowOffset, shadowBlurRadius, shadow);
[[UIColor whiteColor] setStroke];
ovalPath.lineWidth = 2;
[ovalPath stroke];
CGContextRestoreGState(context);
//// Bezier Drawing
UIBezierPath *bezierPath = [UIBezierPath bezierPath];
[bezierPath moveToPoint:CGPointMake(22.36, 11.46)];
[bezierPath addLineToPoint:CGPointMake(18.83, 15)];
[bezierPath addLineToPoint:CGPointMake(22.36, 18.54)];
[bezierPath addLineToPoint:CGPointMake(19.54, 21.36)];
[bezierPath addLineToPoint:CGPointMake(16, 17.83)];
[bezierPath addLineToPoint:CGPointMake(12.46, 21.36)];
[bezierPath addLineToPoint:CGPointMake(9.64, 18.54)];
[bezierPath addLineToPoint:CGPointMake(13.17, 15)];
[bezierPath addLineToPoint:CGPointMake(9.64, 11.46)];
[bezierPath addLineToPoint:CGPointMake(12.46, 8.64)];
[bezierPath addLineToPoint:CGPointMake(16, 12.17)];
[bezierPath addLineToPoint:CGPointMake(19.54, 8.64)];
[bezierPath addLineToPoint:CGPointMake(22.36, 11.46)];
[bezierPath closePath];
CGContextSaveGState(context);
CGContextSetShadowWithColor(context, shadow2Offset, shadow2BlurRadius, shadow2);
[[UIColor whiteColor] setFill];
[bezierPath fill];
CGContextRestoreGState(context);
//// Cleanup
CGGradientRelease(gradient);
CGColorSpaceRelease(colorSpace);
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
@end
|