猎豆优选

ZLPullDownInteractiveTransition.m 5.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. //
  2. // ZLPullDownInteractiveTransition.m
  3. // ZLPhotoBrowser
  4. //
  5. // Created by long on 2018/11/29.
  6. // Copyright © 2018年 long. All rights reserved.
  7. //
  8. #import "ZLPullDownInteractiveTransition.h"
  9. @interface ZLPullDownInteractiveTransition ()
  10. @property (nonatomic, weak) id<UIViewControllerContextTransitioning> transitionContext;
  11. @property (nonatomic, assign) ZLDismissType type;
  12. @property (nonatomic, assign) BOOL shouldStartInteractive;
  13. @property (nonatomic, assign) NSUInteger panCount;
  14. @property (nonatomic, assign) BOOL hadStartDismiss;
  15. @property (nonatomic, strong) UIView *shadowView;
  16. @end
  17. @implementation ZLPullDownInteractiveTransition
  18. - (UIView *)shadowView
  19. {
  20. if (!_shadowView) {
  21. _shadowView = [UIView new];
  22. }
  23. return _shadowView;
  24. }
  25. - (instancetype)initWithViewController:(UIViewController *)vc type:(ZLDismissType)type
  26. {
  27. if (self = [super init]) {
  28. self.viewController = vc;
  29. self.type = type;
  30. UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panAction:)];
  31. [vc.view addGestureRecognizer:pan];
  32. }
  33. return self;
  34. }
  35. - (void)panAction:(UIPanGestureRecognizer *)pan
  36. {
  37. CGPoint p = [pan translationInView:self.viewController.view];
  38. if (pan.state == UIGestureRecognizerStateBegan) {
  39. self.shouldStartInteractive = p.y >= 0;
  40. self.panCount = 0;
  41. } else if (pan.state == UIGestureRecognizerStateChanged) {
  42. if (!self.shouldStartInteractive) return;
  43. self.panCount++;
  44. if (self.panCount == 1 && (p.y < 0 || atan(fabs(p.x)/fabs(p.y)) > M_PI_2/3)) {
  45. // 不满足下拉手势返回
  46. self.shouldStartInteractive = NO;
  47. } else if (_panCount == 1) {
  48. self.shouldStartInteractive = YES;
  49. self.interactive = YES;
  50. if (!self.hadStartDismiss) {
  51. if (self.type == ZLDismissTypeDismiss) {
  52. [self.viewController dismissViewControllerAnimated:YES completion:nil];
  53. } else {
  54. [self.viewController.navigationController popViewControllerAnimated:YES];
  55. }
  56. }
  57. }
  58. if (self.shouldStartInteractive) {
  59. CGFloat percent = 0;
  60. percent = p.y / (self.viewController.view.frame.size.height);
  61. percent = MAX(percent, 0);
  62. [self updatePercent:percent];
  63. [self updateInteractiveTransition:percent];
  64. }
  65. } else if (pan.state == UIGestureRecognizerStateCancelled ||
  66. pan.state == UIGestureRecognizerStateEnded) {
  67. if (!self.shouldStartInteractive || !self.hadStartDismiss) return;
  68. CGPoint vel = [pan velocityInView:self.viewController.view];
  69. CGFloat percent = 0;
  70. percent = p.y / (self.viewController.view.frame.size.height);
  71. percent = MAX(percent, 0);
  72. BOOL dismiss = vel.y > 300 || (percent > 0.4 && vel.y > -300);
  73. if (dismiss) {
  74. [self finishInteractiveTransition];
  75. [self finishAnimate];
  76. } else {
  77. [self cancelInteractiveTransition];
  78. [self cancelAnimate];
  79. }
  80. self.shouldStartInteractive = NO;
  81. self.interactive = NO;
  82. }
  83. }
  84. - (void)startInteractiveTransition:(id<UIViewControllerContextTransitioning>)transitionContext
  85. {
  86. self.transitionContext = transitionContext;
  87. self.hadStartDismiss = YES;
  88. [self beginAnimate];
  89. }
  90. - (void)beginAnimate
  91. {
  92. UIView *fromView = [self.transitionContext viewForKey:UITransitionContextFromViewKey];
  93. UIView *toView = [self.transitionContext viewForKey:UITransitionContextToViewKey];
  94. UIView *containerView = self.transitionContext.containerView;
  95. if (fromView && toView) {
  96. self.shadowView.backgroundColor = [UIColor blackColor];
  97. self.shadowView.frame = toView.bounds;
  98. [containerView addSubview:toView];
  99. [containerView addSubview:self.shadowView];
  100. [containerView addSubview:fromView];
  101. }
  102. }
  103. - (void)updatePercent:(CGFloat)percent
  104. {
  105. UIView *fromView = [self.transitionContext viewForKey:UITransitionContextFromViewKey];
  106. CGRect frame = CGRectMake(0, CGRectGetHeight(fromView.bounds)*percent, CGRectGetWidth(fromView.bounds), CGRectGetHeight(fromView.bounds));
  107. fromView.frame = frame;
  108. self.shadowView.alpha = MIN(1, MAX(0, 1-percent));
  109. }
  110. - (void)finishAnimate
  111. {
  112. self.hadStartDismiss = NO;
  113. UIView *fromView = [self.transitionContext viewForKey:UITransitionContextFromViewKey];
  114. CGRect frame = fromView.frame;
  115. frame.origin.y = frame.size.height;
  116. [UIView animateWithDuration:0.25 animations:^{
  117. fromView.frame = frame;
  118. self.shadowView.alpha = 0;
  119. } completion:^(BOOL finished) {
  120. [self.shadowView removeFromSuperview];
  121. [self.transitionContext completeTransition:!self.transitionContext.transitionWasCancelled];
  122. }];
  123. }
  124. - (void)cancelAnimate
  125. {
  126. self.hadStartDismiss = NO;
  127. UIView *fromView = [self.transitionContext viewForKey:UITransitionContextFromViewKey];
  128. CGRect frame = fromView.frame;
  129. frame.origin.y = 0;
  130. [UIView animateWithDuration:0.25 animations:^{
  131. fromView.frame = frame;
  132. self.shadowView.alpha = 1;
  133. } completion:^(BOOL finished) {
  134. [self.shadowView removeFromSuperview];
  135. [self.transitionContext completeTransition:!self.transitionContext.transitionWasCancelled];
  136. }];
  137. }
  138. @end