PageRenderTime 58ms CodeModel.GetById 0ms RepoModel.GetById 0ms app.codeStats 0ms

/Dependencies/KGModal/KGModal.m

https://gitlab.com/Mr.Tomato/VideoEffects
Objective C | 432 lines | 336 code | 79 blank | 17 comment | 19 complexity | 3162980ac38b523cd7f7f8fdc122d125 MD5 | raw file
  1. //
  2. // KGModal.m
  3. // KGModal
  4. //
  5. // Created by David Keegan on 10/5/12.
  6. // Copyright (c) 2012 David Keegan. All rights reserved.
  7. //
  8. #import "KGModal.h"
  9. #import <QuartzCore/QuartzCore.h>
  10. CGFloat const kFadeInAnimationDuration = 0.3;
  11. CGFloat const kTransformPart1AnimationDuration = 0.2;
  12. CGFloat const kTransformPart2AnimationDuration = 0.1;
  13. CGFloat const kDefaultCloseButtonPadding = 17.0;
  14. NSString *const KGModalGradientViewTapped = @"KGModalGradientViewTapped";
  15. NSString *const KGModalWillShowNotification = @"KGModalWillShowNotification";
  16. NSString *const KGModalDidShowNotification = @"KGModalDidShowNotification";
  17. NSString *const KGModalWillHideNotification = @"KGModalWillHideNotification";
  18. NSString *const KGModalDidHideNotification = @"KGModalDidHideNotification";
  19. @interface KGModalGradientView : UIView
  20. @end
  21. @interface KGModalContainerView : UIView
  22. @property (weak, nonatomic) CALayer *styleLayer;
  23. @property (strong, nonatomic) UIColor *modalBackgroundColor;
  24. @end
  25. @interface KGModalCloseButton : UIButton
  26. @end
  27. @interface KGModalViewController : UIViewController
  28. @property (weak, nonatomic) KGModalGradientView *styleView;
  29. @end
  30. @interface KGModal()
  31. @property (strong, nonatomic) UIWindow *window;
  32. @property (strong, nonatomic) UIViewController *contentViewController;
  33. @property (weak, nonatomic) KGModalViewController *viewController;
  34. @property (weak, nonatomic) KGModalContainerView *containerView;
  35. @property (weak, nonatomic) KGModalCloseButton *closeButton;
  36. @property (weak, nonatomic) UIView *contentView;
  37. @end
  38. @implementation KGModal
  39. + (instancetype)sharedInstance{
  40. static id sharedInstance;
  41. static dispatch_once_t once;
  42. dispatch_once(&once, ^{
  43. sharedInstance = [[[self class] alloc] init];
  44. });
  45. return sharedInstance;
  46. }
  47. - (instancetype)init{
  48. if(!(self = [super init])){
  49. return nil;
  50. }
  51. self.shouldRotate = YES;
  52. self.tapOutsideToDismiss = YES;
  53. self.animateWhenDismissed = YES;
  54. self.closeButtonType = KGModalCloseButtonTypeLeft;
  55. self.modalBackgroundColor = [UIColor colorWithWhite:0 alpha:0.5];
  56. return self;
  57. }
  58. -(void)setCloseButtonType:(KGModalCloseButtonType)closeButtonType {
  59. _closeButtonType = closeButtonType;
  60. if(closeButtonType == KGModalCloseButtonTypeNone){
  61. [self.closeButton setHidden:YES];
  62. }else{
  63. [self.closeButton setHidden:NO];
  64. CGRect closeFrame = self.closeButton.frame;
  65. if(closeButtonType == KGModalCloseButtonTypeRight){
  66. closeFrame.origin.x = round(CGRectGetWidth(self.containerView.frame)-kDefaultCloseButtonPadding-CGRectGetWidth(closeFrame)/2);
  67. }else{
  68. closeFrame.origin.x = 0;
  69. }
  70. self.closeButton.frame = closeFrame;
  71. }
  72. }
  73. - (void)showWithContentView:(UIView *)contentView{
  74. [self showWithContentView:contentView andAnimated:YES];
  75. }
  76. - (void)showWithContentViewController:(UIViewController *)contentViewController{
  77. [self showWithContentViewController:contentViewController andAnimated:YES];
  78. }
  79. - (void)showWithContentViewController:(UIViewController *)contentViewController andAnimated:(BOOL)animated{
  80. self.contentViewController = contentViewController;
  81. [self showWithContentView:contentViewController.view andAnimated:YES];
  82. }
  83. - (void)showWithContentView:(UIView *)contentView andAnimated:(BOOL)animated {
  84. self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
  85. self.window.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight;
  86. self.window.opaque = NO;
  87. KGModalViewController *viewController = [[KGModalViewController alloc] init];
  88. self.window.rootViewController = viewController;
  89. self.viewController = viewController;
  90. CGFloat padding = 17;
  91. CGRect containerViewRect = CGRectInset(contentView.bounds, -padding, -padding);
  92. containerViewRect.origin.x = containerViewRect.origin.y = 0;
  93. containerViewRect.origin.x = round(CGRectGetMidX(self.window.bounds)-CGRectGetMidX(containerViewRect));
  94. containerViewRect.origin.y = round(CGRectGetMidY(self.window.bounds)-CGRectGetMidY(containerViewRect));
  95. KGModalContainerView *containerView = [[KGModalContainerView alloc] initWithFrame:containerViewRect];
  96. containerView.modalBackgroundColor = self.modalBackgroundColor;
  97. containerView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin|UIViewAutoresizingFlexibleRightMargin|
  98. UIViewAutoresizingFlexibleTopMargin|UIViewAutoresizingFlexibleBottomMargin;
  99. containerView.layer.rasterizationScale = [[UIScreen mainScreen] scale];
  100. contentView.frame = (CGRect){padding, padding, contentView.bounds.size};
  101. [containerView addSubview:contentView];
  102. [viewController.view addSubview:containerView];
  103. self.containerView = containerView;
  104. KGModalCloseButton *closeButton = [[KGModalCloseButton alloc] init];
  105. if(self.closeButtonType == KGModalCloseButtonTypeRight){
  106. CGRect closeFrame = closeButton.frame;
  107. closeFrame.origin.x = CGRectGetWidth(containerView.bounds)-CGRectGetWidth(closeFrame);
  108. closeButton.frame = closeFrame;
  109. }
  110. [closeButton addTarget:self action:@selector(closeAction:) forControlEvents:UIControlEventTouchUpInside];
  111. [containerView addSubview:closeButton];
  112. self.closeButton = closeButton;
  113. // Force adjust visibility and placing
  114. [self setCloseButtonType:self.closeButtonType];
  115. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(tapCloseAction:)
  116. name:KGModalGradientViewTapped object:nil];
  117. // The window has to be un-hidden on the main thread
  118. // This will cause the window to display
  119. dispatch_async(dispatch_get_main_queue(), ^{
  120. [[NSNotificationCenter defaultCenter] postNotificationName:KGModalWillShowNotification object:self];
  121. [self.window makeKeyAndVisible];
  122. if(animated){
  123. viewController.styleView.alpha = 0;
  124. [UIView animateWithDuration:kFadeInAnimationDuration animations:^{
  125. viewController.styleView.alpha = 1;
  126. }];
  127. containerView.alpha = 0;
  128. containerView.layer.shouldRasterize = YES;
  129. containerView.transform = CGAffineTransformScale(CGAffineTransformIdentity, 0.4, 0.4);
  130. [UIView animateWithDuration:kTransformPart1AnimationDuration animations:^{
  131. containerView.alpha = 1;
  132. containerView.transform = CGAffineTransformScale(CGAffineTransformIdentity, 1.1, 1.1);
  133. } completion:^(BOOL finished) {
  134. [UIView animateWithDuration:kTransformPart2AnimationDuration delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
  135. containerView.alpha = 1;
  136. containerView.transform = CGAffineTransformScale(CGAffineTransformIdentity, 1, 1);
  137. } completion:^(BOOL finished2) {
  138. containerView.layer.shouldRasterize = NO;
  139. [[NSNotificationCenter defaultCenter] postNotificationName:KGModalDidShowNotification object:self];
  140. }];
  141. }];
  142. }
  143. });
  144. }
  145. - (void)closeAction:(id)sender{
  146. [self hideAnimated:self.animateWhenDismissed];
  147. }
  148. - (void)tapCloseAction:(id)sender{
  149. if(self.tapOutsideToDismiss){
  150. [self hideAnimated:self.animateWhenDismissed];
  151. }
  152. }
  153. - (void)hide{
  154. [self hideAnimated:YES];
  155. }
  156. - (void)hideWithCompletionBlock:(void(^)())completion{
  157. [self hideAnimated:YES withCompletionBlock:completion];
  158. }
  159. - (void)hideAnimated:(BOOL)animated{
  160. [self hideAnimated:animated withCompletionBlock:nil];
  161. }
  162. - (void)hideAnimated:(BOOL)animated withCompletionBlock:(void(^)())completion{
  163. if(!animated){
  164. [self cleanup];
  165. return;
  166. }
  167. dispatch_async(dispatch_get_main_queue(), ^{
  168. [[NSNotificationCenter defaultCenter] postNotificationName:KGModalWillHideNotification object:self];
  169. [UIView animateWithDuration:kFadeInAnimationDuration animations:^{
  170. self.viewController.styleView.alpha = 0;
  171. }];
  172. self.containerView.layer.shouldRasterize = YES;
  173. [UIView animateWithDuration:kTransformPart2AnimationDuration animations:^{
  174. self.containerView.transform = CGAffineTransformScale(CGAffineTransformIdentity, 1.1, 1.1);
  175. } completion:^(BOOL finished){
  176. [UIView animateWithDuration:kTransformPart1AnimationDuration delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
  177. self.containerView.alpha = 0;
  178. self.containerView.transform = CGAffineTransformScale(CGAffineTransformIdentity, 0.4, 0.4);
  179. } completion:^(BOOL finished2){
  180. [self cleanup];
  181. if(completion){
  182. completion();
  183. }
  184. [[NSNotificationCenter defaultCenter] postNotificationName:KGModalDidHideNotification object:self];
  185. }];
  186. }];
  187. });
  188. }
  189. - (void)cleanup{
  190. [[NSNotificationCenter defaultCenter] removeObserver:self];
  191. [self.containerView removeFromSuperview];
  192. [[[[UIApplication sharedApplication] delegate] window] makeKeyWindow];
  193. [self.window removeFromSuperview];
  194. self.contentViewController = nil;
  195. self.window = nil;
  196. }
  197. - (void)setModalBackgroundColor:(UIColor *)modalBackgroundColor{
  198. if(_modalBackgroundColor != modalBackgroundColor){
  199. _modalBackgroundColor = modalBackgroundColor;
  200. self.containerView.modalBackgroundColor = modalBackgroundColor;
  201. }
  202. }
  203. - (void)dealloc{
  204. [self cleanup];
  205. }
  206. @end
  207. @implementation KGModalViewController
  208. - (void)loadView{
  209. self.view = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
  210. }
  211. - (void)viewDidLoad{
  212. [super viewDidLoad];
  213. self.view.backgroundColor = [UIColor clearColor];
  214. self.view.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight;
  215. KGModalGradientView *styleView = [[KGModalGradientView alloc] initWithFrame:self.view.bounds];
  216. styleView.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight;
  217. styleView.opaque = NO;
  218. [self.view addSubview:styleView];
  219. self.styleView = styleView;
  220. }
  221. - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation{
  222. return [[KGModal sharedInstance] shouldRotate];
  223. }
  224. - (BOOL)shouldAutorotate{
  225. return [[KGModal sharedInstance] shouldRotate];
  226. }
  227. @end
  228. @implementation KGModalContainerView
  229. - (instancetype)initWithFrame:(CGRect)frame{
  230. if(!(self = [super initWithFrame:frame])){
  231. return nil;
  232. }
  233. CALayer *styleLayer = [[CALayer alloc] init];
  234. styleLayer.cornerRadius = 4;
  235. styleLayer.shadowColor= [[UIColor blackColor] CGColor];
  236. styleLayer.shadowOffset = CGSizeMake(0, 0);
  237. styleLayer.shadowOpacity = 0.5;
  238. styleLayer.borderWidth = 1;
  239. styleLayer.borderColor = [[UIColor whiteColor] CGColor];
  240. styleLayer.frame = CGRectInset(self.bounds, 12, 12);
  241. [self.layer addSublayer:styleLayer];
  242. self.styleLayer = styleLayer;
  243. return self;
  244. }
  245. - (void)setModalBackgroundColor:(UIColor *)modalBackgroundColor{
  246. if(_modalBackgroundColor != modalBackgroundColor){
  247. _modalBackgroundColor = modalBackgroundColor;
  248. self.styleLayer.backgroundColor = [modalBackgroundColor CGColor];
  249. }
  250. }
  251. @end
  252. @implementation KGModalGradientView
  253. - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
  254. [[NSNotificationCenter defaultCenter] postNotificationName:KGModalGradientViewTapped object:nil];
  255. }
  256. - (void)drawRect:(CGRect)rect{
  257. CGContextRef context = UIGraphicsGetCurrentContext();
  258. if([[KGModal sharedInstance] backgroundDisplayStyle] == KGModalBackgroundDisplayStyleSolid){
  259. [[UIColor colorWithWhite:0 alpha:0.55] set];
  260. CGContextFillRect(context, self.bounds);
  261. }else{
  262. CGContextSaveGState(context);
  263. size_t gradLocationsNum = 2;
  264. CGFloat gradLocations[2] = {0.0f, 1.0f};
  265. CGFloat gradColors[8] = {0, 0, 0, 0.3, 0, 0, 0, 0.8};
  266. CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
  267. CGGradientRef gradient = CGGradientCreateWithColorComponents(colorSpace, gradColors, gradLocations, gradLocationsNum);
  268. CGColorSpaceRelease(colorSpace), colorSpace = NULL;
  269. CGPoint gradCenter= CGPointMake(round(CGRectGetMidX(self.bounds)), round(CGRectGetMidY(self.bounds)));
  270. CGFloat gradRadius = MAX(CGRectGetWidth(self.bounds), CGRectGetHeight(self.bounds));
  271. CGContextDrawRadialGradient(context, gradient, gradCenter, 0, gradCenter, gradRadius, kCGGradientDrawsAfterEndLocation);
  272. CGGradientRelease(gradient), gradient = NULL;
  273. CGContextRestoreGState(context);
  274. }
  275. }
  276. @end
  277. @implementation KGModalCloseButton
  278. - (instancetype)init
  279. {
  280. if(!(self = [super initWithFrame:(CGRect){0, 0, 32, 32}]))
  281. {
  282. return nil;
  283. }
  284. static UIImage *closeButtonImage;
  285. static dispatch_once_t once;
  286. dispatch_once(&once, ^{
  287. closeButtonImage = [self closeButtonImage];
  288. });
  289. [self setBackgroundImage:closeButtonImage forState:UIControlStateNormal];
  290. return self;
  291. }
  292. - (UIImage *)closeButtonImage
  293. {
  294. UIGraphicsBeginImageContextWithOptions(self.bounds.size, NO, 0);
  295. //// General Declarations
  296. CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
  297. CGContextRef context = UIGraphicsGetCurrentContext();
  298. //// Color Declarations
  299. UIColor *topGradient = [UIColor colorWithRed:0.21 green:0.21 blue:0.21 alpha:0.9];
  300. UIColor *bottomGradient = [UIColor colorWithRed:0.03 green:0.03 blue:0.03 alpha:0.9];
  301. //// Gradient Declarations
  302. NSArray *gradientColors = @[(id)topGradient.CGColor,
  303. (id)bottomGradient.CGColor];
  304. CGFloat gradientLocations[] = {0, 1};
  305. CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, (__bridge CFArrayRef)gradientColors, gradientLocations);
  306. //// Shadow Declarations
  307. CGColorRef shadow = [UIColor blackColor].CGColor;
  308. CGSize shadowOffset = CGSizeMake(0, 1);
  309. CGFloat shadowBlurRadius = 3;
  310. CGColorRef shadow2 = [UIColor blackColor].CGColor;
  311. CGSize shadow2Offset = CGSizeMake(0, 1);
  312. CGFloat shadow2BlurRadius = 0;
  313. //// Oval Drawing
  314. UIBezierPath *ovalPath = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(4, 3, 24, 24)];
  315. CGContextSaveGState(context);
  316. [ovalPath addClip];
  317. CGContextDrawLinearGradient(context, gradient, CGPointMake(16, 3), CGPointMake(16, 27), 0);
  318. CGContextRestoreGState(context);
  319. CGContextSaveGState(context);
  320. CGContextSetShadowWithColor(context, shadowOffset, shadowBlurRadius, shadow);
  321. [[UIColor whiteColor] setStroke];
  322. ovalPath.lineWidth = 2;
  323. [ovalPath stroke];
  324. CGContextRestoreGState(context);
  325. //// Bezier Drawing
  326. UIBezierPath *bezierPath = [UIBezierPath bezierPath];
  327. [bezierPath moveToPoint:CGPointMake(22.36, 11.46)];
  328. [bezierPath addLineToPoint:CGPointMake(18.83, 15)];
  329. [bezierPath addLineToPoint:CGPointMake(22.36, 18.54)];
  330. [bezierPath addLineToPoint:CGPointMake(19.54, 21.36)];
  331. [bezierPath addLineToPoint:CGPointMake(16, 17.83)];
  332. [bezierPath addLineToPoint:CGPointMake(12.46, 21.36)];
  333. [bezierPath addLineToPoint:CGPointMake(9.64, 18.54)];
  334. [bezierPath addLineToPoint:CGPointMake(13.17, 15)];
  335. [bezierPath addLineToPoint:CGPointMake(9.64, 11.46)];
  336. [bezierPath addLineToPoint:CGPointMake(12.46, 8.64)];
  337. [bezierPath addLineToPoint:CGPointMake(16, 12.17)];
  338. [bezierPath addLineToPoint:CGPointMake(19.54, 8.64)];
  339. [bezierPath addLineToPoint:CGPointMake(22.36, 11.46)];
  340. [bezierPath closePath];
  341. CGContextSaveGState(context);
  342. CGContextSetShadowWithColor(context, shadow2Offset, shadow2BlurRadius, shadow2);
  343. [[UIColor whiteColor] setFill];
  344. [bezierPath fill];
  345. CGContextRestoreGState(context);
  346. //// Cleanup
  347. CGGradientRelease(gradient);
  348. CGColorSpaceRelease(colorSpace);
  349. UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
  350. UIGraphicsEndImageContext();
  351. return image;
  352. }
  353. @end