CWDrawerTransition.m 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. //
  2. // CWDrawerTransition.m
  3. // ViewControllerTransition
  4. //
  5. // Created by chavez on 2017/6/27.
  6. // Copyright © 2017年 chavez. All rights reserved.
  7. //
  8. #import "CWDrawerTransition.h"
  9. #import <objc/runtime.h>
  10. @interface CWDrawerTransition ()
  11. @property (nonatomic,weak) CWLateralSlideConfiguration *configuration;
  12. @end
  13. @implementation CWDrawerTransition
  14. {
  15. CWDrawerTransitiontype _TransitionType;
  16. CWDrawerAnimationType _animationType;
  17. CGFloat _hiddenDelayTime;
  18. }
  19. - (instancetype)initWithTransitionType:(CWDrawerTransitiontype)transitionType animationType:(CWDrawerAnimationType)animationType configuration:(CWLateralSlideConfiguration *)configuration {
  20. if (self = [super init]) {
  21. _TransitionType = transitionType;
  22. _animationType = animationType;
  23. _configuration = configuration;
  24. if (_TransitionType == CWDrawerTransitiontypeHidden)
  25. [self setupHiddenAnimationDelayTime];
  26. }
  27. return self;
  28. }
  29. + (instancetype)transitionWithType:(CWDrawerTransitiontype)transitionType animationType:(CWDrawerAnimationType)animationType configuration:(CWLateralSlideConfiguration *)configuration {
  30. return [[self alloc] initWithTransitionType:transitionType animationType:animationType configuration:configuration];
  31. }
  32. - (void)setupHiddenAnimationDelayTime {
  33. _hiddenDelayTime = 0;
  34. if ([UIDevice currentDevice].systemVersion.floatValue >= 11.0) {
  35. _hiddenDelayTime = 0.03;
  36. }
  37. }
  38. #pragma mark - UIViewControllerAnimatedTransitioning
  39. - (NSTimeInterval)transitionDuration:(nullable id <UIViewControllerContextTransitioning>)transitionContext {
  40. return _TransitionType == CWDrawerTransitiontypeShow ? self.configuration.showAnimDuration : self.configuration.HiddenAnimDuration;
  41. }
  42. - (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext {
  43. switch (_TransitionType) {
  44. case CWDrawerTransitiontypeShow:
  45. [self animationViewShow:transitionContext];
  46. break;
  47. case CWDrawerTransitiontypeHidden:
  48. [self animationViewHidden:transitionContext];
  49. break;
  50. default:
  51. break;
  52. }
  53. }
  54. #pragma mark - private methods
  55. - (void)animationViewShow:(id <UIViewControllerContextTransitioning>)transitionContext {
  56. if (_animationType == CWDrawerAnimationTypeDefault) {
  57. [self defaultAnimationWithContext:transitionContext];
  58. }else if (_animationType == CWDrawerAnimationTypeMask) {
  59. [self maskAnimationWithContext:transitionContext];
  60. }else {
  61. }
  62. }
  63. - (void)animationViewHidden:(id <UIViewControllerContextTransitioning>)transitionContext {
  64. UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
  65. UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
  66. CWMaskView *maskView = [CWMaskView shareInstance];
  67. // 导航控制器的navigationBar在导航栏先隐藏后显示的情况下会被删除,所以过滤掉导航控制器
  68. if (![toVC isKindOfClass:[UINavigationController class]]) {
  69. for (UIView *view in toVC.view.subviews) {
  70. if (![maskView.toViewSubViews containsObject:view]) {
  71. [view removeFromSuperview];
  72. }
  73. }
  74. }
  75. UIView *containerView = [transitionContext containerView];
  76. UIImageView *backImageView;
  77. if ([containerView.subviews.firstObject isKindOfClass:[UIImageView class]])
  78. backImageView = containerView.subviews.firstObject;
  79. [UIView animateKeyframesWithDuration:[self transitionDuration:transitionContext] delay:_hiddenDelayTime options:UIViewKeyframeAnimationOptionCalculationModeLinear animations:^{
  80. [UIView addKeyframeWithRelativeStartTime:0 relativeDuration:1.0 animations:^{
  81. toVC.view.transform = CGAffineTransformIdentity;
  82. fromVC.view.transform = CGAffineTransformIdentity;
  83. maskView.alpha = 0;
  84. backImageView.transform = CGAffineTransformMakeScale(1.4, 1.4);
  85. }];
  86. } completion:^(BOOL finished) {
  87. if (![transitionContext transitionWasCancelled]) {
  88. maskView.toViewSubViews = nil;
  89. [CWMaskView releaseInstance];
  90. [backImageView removeFromSuperview];
  91. }
  92. [transitionContext completeTransition:![transitionContext transitionWasCancelled]];
  93. }];
  94. }
  95. - (void)defaultAnimationWithContext:(id <UIViewControllerContextTransitioning>)transitionContext {
  96. UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
  97. UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
  98. CWMaskView *maskView = [CWMaskView shareInstance];
  99. maskView.frame = fromVC.view.bounds;
  100. [fromVC.view addSubview:maskView];
  101. UIView *containerView = [transitionContext containerView];
  102. UIImageView *imageV;
  103. if (self.configuration.backImage) {
  104. imageV = [[UIImageView alloc] initWithFrame:containerView.bounds];
  105. imageV.image = self.configuration.backImage;
  106. imageV.transform = CGAffineTransformMakeScale(1.4, 1.4);
  107. imageV.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight;
  108. }
  109. [containerView addSubview:imageV];
  110. CGFloat width = self.configuration.distance;
  111. CGFloat x = - width / 2;
  112. CGFloat ret = 1;
  113. if (self.configuration.direction == CWDrawerTransitionFromRight) {
  114. x = kCWSCREENWIDTH - width / 2;
  115. ret = -1;
  116. }
  117. toVC.view.frame = CGRectMake(x, 0, CGRectGetWidth(containerView.frame), CGRectGetHeight(containerView.frame));
  118. [containerView addSubview:toVC.view];
  119. [containerView addSubview:fromVC.view];
  120. // 计算缩放后需要平移的距离
  121. CGFloat translationX = width - (kCWSCREENWIDTH * (1 - self.configuration.scaleY) / 2);
  122. CGAffineTransform t1 = CGAffineTransformMakeScale(self.configuration.scaleY, self.configuration.scaleY);
  123. CGAffineTransform t2 = CGAffineTransformMakeTranslation(ret * translationX, 0);
  124. CGAffineTransform fromVCTransform = CGAffineTransformConcat(t1, t2);
  125. CGAffineTransform toVCTransform;
  126. if (self.configuration.direction == CWDrawerTransitionFromRight) {
  127. toVCTransform = CGAffineTransformMakeTranslation(ret * (x - CGRectGetWidth(containerView.frame) + width), 0);
  128. }else {
  129. toVCTransform = CGAffineTransformMakeTranslation(ret * width / 2, 0);
  130. }
  131. [UIView animateKeyframesWithDuration:[self transitionDuration:transitionContext] delay:0 options:0 animations:^{
  132. [UIView addKeyframeWithRelativeStartTime:0.0 relativeDuration:1.0 animations:^{
  133. fromVC.view.transform = fromVCTransform;
  134. toVC.view.transform = toVCTransform;
  135. imageV.transform = CGAffineTransformIdentity;
  136. maskView.alpha = self.configuration.maskAlpha;
  137. }];
  138. } completion:^(BOOL finished) {
  139. if (![transitionContext transitionWasCancelled]) {
  140. maskView.userInteractionEnabled = YES;
  141. // 导航控制器的navigationbar可能是先隐藏再显示,这里会不在fromVC.view.subviews,上面移除时会有问题
  142. if (![toVC isKindOfClass:[UINavigationController class]]) {
  143. maskView.toViewSubViews = fromVC.view.subviews;
  144. }
  145. [transitionContext completeTransition:YES];
  146. [containerView addSubview:fromVC.view];
  147. }else {
  148. [imageV removeFromSuperview];
  149. [CWMaskView releaseInstance];
  150. [transitionContext completeTransition:NO];
  151. }
  152. }];
  153. }
  154. - (void)maskAnimationWithContext:(id <UIViewControllerContextTransitioning>)transitionContext {
  155. UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
  156. UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
  157. CWMaskView *maskView = [CWMaskView shareInstance];
  158. maskView.frame = fromVC.view.bounds;
  159. [fromVC.view addSubview:maskView];
  160. UIView *containerView = [transitionContext containerView];
  161. CGFloat width = self.configuration.distance;
  162. CGFloat x = - width;
  163. CGFloat ret = 1;
  164. if (self.configuration.direction == CWDrawerTransitionFromRight) {
  165. x = kCWSCREENWIDTH;
  166. ret = -1;
  167. }
  168. toVC.view.frame = CGRectMake(x, 0, width, CGRectGetHeight(containerView.frame));
  169. [containerView addSubview:fromVC.view];
  170. [containerView addSubview:toVC.view];
  171. CGAffineTransform toVCTransiform = CGAffineTransformMakeTranslation(ret * width , 0);
  172. [UIView animateKeyframesWithDuration:[self transitionDuration:transitionContext] delay:0 options:0 animations:^{
  173. [UIView addKeyframeWithRelativeStartTime:0.0 relativeDuration:1.0 animations:^{
  174. toVC.view.transform = toVCTransiform;
  175. maskView.alpha = self.configuration.maskAlpha;
  176. }];
  177. } completion:^(BOOL finished) {
  178. if (![transitionContext transitionWasCancelled]) {
  179. [transitionContext completeTransition:YES];
  180. maskView.toViewSubViews = fromVC.view.subviews;
  181. [containerView addSubview:fromVC.view];
  182. [containerView bringSubviewToFront:toVC.view];
  183. maskView.userInteractionEnabled = YES;
  184. }else {
  185. [CWMaskView releaseInstance];
  186. [transitionContext completeTransition:NO];
  187. }
  188. }];
  189. }
  190. - (void)dealloc {
  191. // NSLog(@"%s",__func__);
  192. }
  193. @end
  194. @implementation CWMaskView
  195. static CWMaskView *cw_shareInstance = nil;
  196. static dispatch_once_t cw_onceToken;
  197. + (instancetype)shareInstance {
  198. dispatch_once(&cw_onceToken, ^{
  199. cw_shareInstance = [[CWMaskView alloc] init];
  200. });
  201. return cw_shareInstance;
  202. }
  203. + (void)releaseInstance{
  204. [cw_shareInstance removeFromSuperview];
  205. cw_onceToken = 0;
  206. cw_shareInstance = nil;
  207. }
  208. - (void)dealloc {
  209. // NSLog(@"mask dealloc");
  210. }
  211. - (instancetype)initWithFrame:(CGRect)frame {
  212. if (self = [super initWithFrame:frame]) {
  213. self.backgroundColor = [UIColor blackColor];
  214. self.alpha = 0;
  215. self.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight;
  216. UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(singleTap)];
  217. tap.numberOfTapsRequired = 1;
  218. [self addGestureRecognizer:tap];
  219. UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handleGesture:)];
  220. [self addGestureRecognizer:pan];
  221. }
  222. return self;
  223. }
  224. - (void)singleTap {
  225. [[NSNotificationCenter defaultCenter] postNotificationName:CWLateralSlideTapNoticationKey object:self];
  226. }
  227. - (void)handleGesture:(UIPanGestureRecognizer *)pan {
  228. [[NSNotificationCenter defaultCenter] postNotificationName:CWLateralSlidePanNoticationKey object:pan];
  229. }
  230. // 屏蔽掉touchesbegin的响应链
  231. - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { }
  232. @end
  233. NSString *const CWLateralSlideMaskViewKey = @"CWLateralSlideMaskViewKey";
  234. NSString *const CWLateralSlideAnimatorKey = @"CWLateralSlideAnimatorKey";
  235. NSString *const CWLateralSlideInterativeKey = @"CWLateralSlideInterativeKey";
  236. NSString *const CWLateralSlidePanNoticationKey = @"CWLateralSlidePanNoticationKey";
  237. NSString *const CWLateralSlideTapNoticationKey = @"CWLateralSlideTapNoticationKey";
  238. NSString *const CWLateralSlideDirectionKey = @"CWLateralSlideDirectionKey";