YBIBAnimatedTransition.m 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. //
  2. // YBIBAnimatedTransition.m
  3. // YBImageBrowserDemo
  4. //
  5. // Created by 波儿菜 on 2019/6/6.
  6. // Copyright © 2019 波儿菜. All rights reserved.
  7. //
  8. #import "YBIBAnimatedTransition.h"
  9. extern CGFloat YBIBRotationAngle(UIDeviceOrientation startOrientation, UIDeviceOrientation endOrientation);
  10. @implementation YBIBAnimatedTransition
  11. #pragma mark - life cycle
  12. - (instancetype)init {
  13. self = [super init];
  14. if (self) {
  15. _showType = _hideType = YBIBTransitionTypeCoherent;
  16. _showDuration = _hideDuration = 0.25;
  17. }
  18. return self;
  19. }
  20. #pragma mark - <YBIBAnimationHandler>
  21. - (void)yb_showTransitioningWithContainer:(UIView *)container startView:(__kindof UIView *)startView startImage:(UIImage *)startImage endFrame:(CGRect)endFrame orientation:(UIDeviceOrientation)orientation completion:(void (^)(void))completion {
  22. YBIBTransitionType type = self.showType;
  23. if (type == YBIBTransitionTypeCoherent) {
  24. if (CGRectIsEmpty(endFrame) || !startView || orientation != (UIDeviceOrientation)UIApplication.sharedApplication.statusBarOrientation) {
  25. type = YBIBTransitionTypeFade;
  26. }
  27. }
  28. switch (type) {
  29. case YBIBTransitionTypeNone: {
  30. completion();
  31. }
  32. break;
  33. case YBIBTransitionTypeFade: {
  34. BOOL animateValid = !CGRectIsEmpty(endFrame) && startView;
  35. UIImageView *animateImageView;
  36. if (animateValid) {
  37. animateImageView = [self imageViewAssimilateToView:startView];
  38. animateImageView.frame = endFrame;
  39. animateImageView.image = startImage;
  40. [container addSubview:animateImageView];
  41. }
  42. CGFloat rawAlpha = container.alpha;
  43. container.alpha = 0;
  44. if (!animateValid) completion();
  45. [UIView animateWithDuration:self.showDuration animations:^{
  46. container.alpha = rawAlpha;
  47. } completion:^(BOOL finished) {
  48. if (animateValid) {
  49. [animateImageView removeFromSuperview];
  50. completion();
  51. }
  52. }];
  53. }
  54. break;
  55. case YBIBTransitionTypeCoherent: {
  56. UIImageView *animateImageView = [self imageViewAssimilateToView:startView];
  57. animateImageView.frame = [startView convertRect:startView.bounds toView:container];
  58. animateImageView.image = startImage;
  59. [container addSubview:animateImageView];
  60. UIColor *rawBackgroundColor = container.backgroundColor;
  61. container.backgroundColor = [rawBackgroundColor colorWithAlphaComponent:0];
  62. [UIView animateWithDuration:self.showDuration animations:^{
  63. animateImageView.frame = endFrame;
  64. container.backgroundColor = rawBackgroundColor;
  65. } completion:^(BOOL finished) {
  66. completion();
  67. // Disappear smoothly.
  68. [UIView animateWithDuration:0.2 animations:^{
  69. animateImageView.alpha = 0;
  70. } completion:^(BOOL finished) {
  71. [animateImageView removeFromSuperview];
  72. }];
  73. }];
  74. }
  75. break;
  76. }
  77. }
  78. - (void)yb_hideTransitioningWithContainer:(UIView *)container startView:(__kindof UIView *)startView endView:(UIView *)endView orientation:(UIDeviceOrientation)orientation completion:(void (^)(void))completion {
  79. YBIBTransitionType type = self.hideType;
  80. if (type == YBIBTransitionTypeCoherent && (!startView || !endView)) {
  81. type = YBIBTransitionTypeFade;
  82. }
  83. switch (type) {
  84. case YBIBTransitionTypeNone: {
  85. completion();
  86. }
  87. break;
  88. case YBIBTransitionTypeFade: {
  89. CGFloat rawAlpha = container.alpha;
  90. [UIView animateWithDuration:self.hideDuration animations:^{
  91. container.alpha = 0;
  92. } completion:^(BOOL finished) {
  93. completion();
  94. container.alpha = rawAlpha;
  95. }];
  96. }
  97. break;
  98. case YBIBTransitionTypeCoherent: {
  99. CGRect startFrame = startView.frame;
  100. CGRect endFrame = [endView convertRect:endView.bounds toView:startView.superview];
  101. UIColor *rawBackgroundColor = container.backgroundColor;
  102. [UIView animateWithDuration:self.hideDuration animations:^{
  103. container.backgroundColor = [rawBackgroundColor colorWithAlphaComponent:0];
  104. startView.contentMode = endView.contentMode;
  105. CGAffineTransform transform = startView.transform;
  106. UIDeviceOrientation statusBarOrientation = (UIDeviceOrientation)UIApplication.sharedApplication.statusBarOrientation;
  107. if (orientation != statusBarOrientation) {
  108. transform = CGAffineTransformRotate(transform, YBIBRotationAngle(orientation, statusBarOrientation));
  109. }
  110. if ([startView isKindOfClass:UIImageView.self]) {
  111. startView.frame = endFrame;
  112. startView.transform = transform;
  113. } else {
  114. CGFloat scale = MAX(endFrame.size.width / startFrame.size.width, endFrame.size.height / startFrame.size.height);
  115. startView.center = CGPointMake(endFrame.size.width * startView.layer.anchorPoint.x + endFrame.origin.x, endFrame.size.height * startView.layer.anchorPoint.y + endFrame.origin.y);
  116. startView.transform = CGAffineTransformScale(transform, scale, scale);
  117. }
  118. } completion:^(BOOL finished) {
  119. completion();
  120. container.backgroundColor = rawBackgroundColor;
  121. }];
  122. }
  123. break;
  124. }
  125. }
  126. #pragma mark - private
  127. - (UIImageView *)imageViewAssimilateToView:(nullable __kindof UIView *)view {
  128. UIImageView *animateImageView = [UIImageView new];
  129. if ([view isKindOfClass:UIImageView.self]) {
  130. animateImageView.contentMode = view.contentMode;
  131. } else {
  132. animateImageView.contentMode = UIViewContentModeScaleAspectFill;
  133. }
  134. animateImageView.layer.masksToBounds = view.layer.masksToBounds;
  135. animateImageView.layer.cornerRadius = view.layer.cornerRadius;
  136. animateImageView.layer.backgroundColor = view.layer.backgroundColor;
  137. return animateImageView;
  138. }
  139. @end