TOPasscodeViewControllerAnimatedTransitioning.m 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. //
  2. // TOPasscodeViewControllerAnimatedTransitioning.m
  3. //
  4. // Copyright 2017 Timothy Oliver. All rights reserved.
  5. //
  6. // Permission is hereby granted, free of charge, to any person obtaining a copy
  7. // of this software and associated documentation files (the "Software"), to
  8. // deal in the Software without restriction, including without limitation the
  9. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  10. // sell copies of the Software, and to permit persons to whom the Software is
  11. // furnished to do so, subject to the following conditions:
  12. //
  13. // The above copyright notice and this permission notice shall be included in
  14. // all copies or substantial portions of the Software.
  15. //
  16. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  17. // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  19. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  20. // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
  21. // IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  22. #import "TOPasscodeViewControllerAnimatedTransitioning.h"
  23. #import "TOPasscodeViewController.h"
  24. #import "TOPasscodeView.h"
  25. @interface TOPasscodeViewControllerAnimatedTransitioning ()
  26. @property (nonatomic, weak) TOPasscodeViewController *passcodeViewController;
  27. @end
  28. @implementation TOPasscodeViewControllerAnimatedTransitioning
  29. - (instancetype)initWithPasscodeViewController:(TOPasscodeViewController *)passcodeViewController dismissing:(BOOL)dismissing success:(BOOL)success
  30. {
  31. if (self = [super init]) {
  32. _passcodeViewController = passcodeViewController;
  33. _dismissing = dismissing;
  34. _success = success;
  35. }
  36. return self;
  37. }
  38. - (NSTimeInterval)transitionDuration:(nullable id <UIViewControllerContextTransitioning>)transitionContext
  39. {
  40. return 0.35f;
  41. }
  42. - (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext
  43. {
  44. BOOL isPhone = UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone;
  45. UIView *containerView = transitionContext.containerView;
  46. UIVisualEffectView *backgroundEffectView = self.passcodeViewController.backgroundEffectView;
  47. UIView *backgroundView = self.passcodeViewController.backgroundView;
  48. UIVisualEffect *backgroundEffect = backgroundEffectView.effect;
  49. TOPasscodeView *passcodeView = self.passcodeViewController.passcodeView;
  50. // Set the initial properties when presenting
  51. if (!self.dismissing) {
  52. backgroundEffectView.effect = nil;
  53. backgroundView.alpha = 0.0f;
  54. self.passcodeViewController.view.frame = containerView.bounds;
  55. [containerView addSubview:self.passcodeViewController.view];
  56. }
  57. else {
  58. UIViewController *baseController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
  59. if (baseController.view.superview == nil) {
  60. [containerView insertSubview:baseController.view atIndex:0];
  61. }
  62. }
  63. CGFloat alpha = self.dismissing ? 1.0f : 0.0f;
  64. passcodeView.contentAlpha = alpha;
  65. // Animate the accessory views
  66. if (isPhone) {
  67. self.passcodeViewController.leftAccessoryButton.alpha = alpha;
  68. self.passcodeViewController.rightAccessoryButton.alpha = alpha;
  69. self.passcodeViewController.cancelButton.alpha = alpha;
  70. self.passcodeViewController.biometricButton.alpha = alpha;
  71. }
  72. id animationBlock = ^{
  73. backgroundEffectView.effect = self.dismissing ? nil : backgroundEffect;
  74. backgroundView.alpha = self.dismissing ? 0.0f : 1.0f;
  75. CGFloat toAlpha = self.dismissing ? 0.0f : 1.0f;
  76. passcodeView.contentAlpha = toAlpha;
  77. if (isPhone) {
  78. self.passcodeViewController.leftAccessoryButton.alpha = toAlpha;
  79. self.passcodeViewController.rightAccessoryButton.alpha = toAlpha;
  80. self.passcodeViewController.cancelButton.alpha = toAlpha;
  81. self.passcodeViewController.biometricButton.alpha = toAlpha;
  82. }
  83. };
  84. id completedBlock = ^(BOOL completed) {
  85. backgroundEffectView.effect = backgroundEffect;
  86. [transitionContext completeTransition:completed];
  87. };
  88. // If we're animating out from a successful passcode, play a zooming out animation
  89. // to give some more context
  90. if (self.success && self.dismissing) {
  91. CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform"];
  92. animation.duration = [self transitionDuration:transitionContext];
  93. animation.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(0.9f, 0.9f, 1)];
  94. animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
  95. [passcodeView.layer addAnimation:animation forKey:@"transform"];
  96. }
  97. [UIView animateWithDuration:[self transitionDuration:transitionContext]
  98. delay:0.0f
  99. options:UIViewAnimationOptionAllowUserInteraction
  100. animations:animationBlock
  101. completion:completedBlock];
  102. }
  103. @end