Custom UIViewController Transitions
Upcoming SlideShare
Loading in...5
×
 

Like this? Share it with your network

Share

Custom UIViewController Transitions

on

  • 873 views

Creating custom animated and interactive transitions between UIViewControllers using iOS 7.0 API.

Creating custom animated and interactive transitions between UIViewControllers using iOS 7.0 API.

Statistics

Views

Total Views
873
Views on SlideShare
873
Embed Views
0

Actions

Likes
3
Downloads
7
Comments
0

0 Embeds 0

No embeds

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

Custom UIViewController Transitions Presentation Transcript

  • 1. Custom UIViewController Transitions Ján Ilavský - @split82
  • 2. iPhone OS 3.0
  • 3. iOS 7
  • 4. Modal View Controller - (void)presentViewController:animated:completion: ! - (void)dismissViewControllerAnimated:completion:
  • 5. UIModalTransitionStyle modalTransitionStyle
  • 6. typedef NS_ENUM(NSInteger, UIModalTransitionStyle) { UIModalTransitionStyleCoverVertical = 0, UIModalTransitionStyleFlipHorizontal, UIModalTransitionStyleCrossDissolve, #if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_3_2 UIModalTransitionStylePartialCurl, #endif };
  • 7. UIModalPresentationStyle modalPresentationStyle
  • 8. typedef NS_ENUM(NSInteger, UIModalPresentationStyle) { UIModalPresentationFullScreen = 0, #if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_3_2 UIModalPresentationPageSheet, UIModalPresentationFormSheet, UIModalPresentationCurrentContext, #endif #if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_7_0 UIModalPresentationCustom, UIModalPresentationNone = -1, #endif };
  • 9. typedef NS_ENUM(NSInteger, UIModalPresentationStyle) { UIModalPresentationFullScreen = 0, #if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_3_2 UIModalPresentationPageSheet, UIModalPresentationFormSheet, UIModalPresentationCurrentContext, #endif #if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_7_0 UIModalPresentationCustom, UIModalPresentationNone = -1, #endif };
  • 10. Custom Fullscreen Non-interactive Transitions
  • 11. Demo
  • 12. TestViewController *viewController = [TestViewController new]; ! viewController.transitioningDelegate = ??? ! [self presentViewController:viewController animated:YES completion:nil];
  • 13. TestViewController *viewController = [TestViewController new]; ! viewController.transitioningDelegate = ??? ! [self presentViewController:viewController animated:YES completion:nil];
  • 14. @protocol UIViewControllerTransitioningDelegate <NSObject> ! @optional ! ! - (id <UIViewControllerAnimatedTransitioning>) animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController: (UIViewController *)source; ! ! - (id <UIViewControllerAnimatedTransitioning>) animationControllerForDismissedController:(UIViewController *)dismissed; ! ! - (id <UIViewControllerInteractiveTransitioning>)interactionControllerForPresentation:(id <UIViewControllerAnimatedTransitioning>)animator; ! ! - (id <UIViewControllerInteractiveTransitioning>)interactionControllerForDismissal: (id <UIViewControllerAnimatedTransitioning>)animator; ! ! @end
  • 15. @protocol UIViewControllerTransitioningDelegate <NSObject> ! @optional ! ! - (id <UIViewControllerAnimatedTransitioning>) animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController: (UIViewController *)source; ! ! - (id <UIViewControllerAnimatedTransitioning>) animationControllerForDismissedController:(UIViewController *)dismissed; ! ! - (id <UIViewControllerInteractiveTransitioning>)interactionControllerForPresentation:(id <UIViewControllerAnimatedTransitioning>)animator; ! ! - (id <UIViewControllerInteractiveTransitioning>)interactionControllerForDismissal: (id <UIViewControllerAnimatedTransitioning>)animator; ! ! @end
  • 16. @protocol UIViewControllerTransitioningDelegate <NSObject> ! @optional ! ! - (id <UIViewControllerAnimatedTransitioning>) animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController: (UIViewController *)source; ! ! - (id <UIViewControllerAnimatedTransitioning>) animationControllerForDismissedController:(UIViewController *)dismissed; ! ! - (id <UIViewControllerInteractiveTransitioning>)interactionControllerForPresentation:(id <UIViewControllerAnimatedTransitioning>)animator; ! ! - (id <UIViewControllerInteractiveTransitioning>)interactionControllerForDismissal: (id <UIViewControllerAnimatedTransitioning>)animator; ! ! @end
  • 17. UIViewController UIViewController id <UIViewControllerTransitioningDelegate> transitioningDelegate animationControllerForPresentedController… animationControllerForDismissedController id <UIViewControllerAnimatedTransitioning> id <UIViewControllerAnimatedTransitioning> present dismiss
  • 18. @protocol UIViewControllerAnimatedTransitioning <NSObject> ! ! - (NSTimeInterval)transitionDuration:(id <UIViewControllerContextTransitioning>)transitionContext; ! - (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext; ! ! @optional ! - (void)animationEnded:(BOOL)transitionCompleted; ! @end
  • 19. @protocol UIViewControllerAnimatedTransitioning <NSObject> ! ! - (NSTimeInterval)transitionDuration:(id <UIViewControllerContextTransitioning>)transitionContext; ! - (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext; ! ! @optional ! - (void)animationEnded:(BOOL)transitionCompleted; ! @end
  • 20. UIView UIView UIViewController UIViewController
  • 21. @protocol UIViewControllerAnimatedTransitioning <NSObject> ! ! - (NSTimeInterval)transitionDuration:(id <UIViewControllerContextTransitioning>)transitionContext; ! - (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext; ! ! @optional ! - (void)animationEnded:(BOOL)transitionCompleted; ! @end
  • 22. @protocol UIViewControllerAnimatedTransitioning <NSObject> ! ! - (NSTimeInterval)transitionDuration:(id <UIViewControllerContextTransitioning>)transitionContext; ! - (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext; ! ! @optional ! - (void)animationEnded:(BOOL)transitionCompleted; ! @end
  • 23. UIViewController *fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey]; ! UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey]; ! ! toViewController.view.alpha = 0.0f; toViewController.view.frame = [transitionContext finalFrameForViewController:toViewController]; ! [transitionContext.containerView addSubview:toViewController.view]; [UIView animateWithDuration:self.duration delay:0.0 options:0 animations:^{ toViewController.view.alpha = 1.0f; } completion:^(BOOL finished) { [fromViewController.view removeFromSuperview]; [transitionContext completeTransition:YES]; }];
  • 24. ! Container View UIView UIView UIViewController UIViewController
  • 25. UIViewController *fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey]; ! UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey]; ! ! toViewController.view.alpha = 0.0f; toViewController.view.frame = [transitionContext finalFrameForViewController:toViewController]; ! [transitionContext.containerView addSubview:toViewController.view]; [UIView animateWithDuration:self.duration delay:0.0 options:0 animations:^{ toViewController.view.alpha = 1.0f; } completion:^(BOOL finished) { [fromViewController.view removeFromSuperview]; [transitionContext completeTransition:YES]; }];
  • 26. UIViewController *fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey]; ! UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey]; ! ! toViewController.view.alpha = 0.0f; toViewController.view.frame = [transitionContext finalFrameForViewController:toViewController]; ! [transitionContext.containerView addSubview:toViewController.view]; [UIView animateWithDuration:self.duration delay:0.0 options:0 animations:^{ toViewController.view.alpha = 1.0f; } completion:^(BOOL finished) { [fromViewController.view removeFromSuperview]; [transitionContext completeTransition:YES]; }];
  • 27. initialFrameForViewController finalFrameForViewController from CGRectZero to CGRectZero
  • 28. UIViewController *fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey]; ! UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey]; ! ! toViewController.view.alpha = 0.0f; toViewController.view.frame = [transitionContext finalFrameForViewController:toViewController]; ! [transitionContext.containerView addSubview:toViewController.view]; [UIView animateWithDuration:self.duration delay:0.0 options:0 animations:^{ toViewController.view.alpha = 1.0f; } completion:^(BOOL finished) { [fromViewController.view removeFromSuperview]; [transitionContext completeTransition:YES]; }];
  • 29. UIViewController *fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey]; ! UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey]; ! ! toViewController.view.alpha = 0.0f; toViewController.view.frame = [transitionContext finalFrameForViewController:toViewController]; ! [transitionContext.containerView addSubview:toViewController.view]; [UIView animateWithDuration:self.duration delay:0.0 options:0 animations:^{ toViewController.view.alpha = 1.0f; } completion:^(BOOL finished) { [fromViewController.view removeFromSuperview]; [transitionContext completeTransition:YES]; }];
  • 30. UIViewController *fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey]; ! UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey]; ! ! toViewController.view.alpha = 0.0f; toViewController.view.frame = [transitionContext finalFrameForViewController:toViewController]; ! [transitionContext.containerView addSubview:toViewController.view]; [UIView animateWithDuration:self.duration delay:0.0 options:0 animations:^{ toViewController.view.alpha = 1.0f; } completion:^(BOOL finished) { //[fromViewController.view removeFromSuperview]; [transitionContext completeTransition:YES]; }];
  • 31. Custom Non-Fullscreen Non-interactive Transitions
  • 32. TestViewController *viewController = [TestViewController new]; ! viewController.modalPresentationStyle = UIModalPresentationCustom; viewController.transitioningDelegate = ??? ! [self presentViewController:viewController animated:YES completion:nil];
  • 33. UIView UIView
  • 34. Demo
  • 35. Presentation != Dismissal
  • 36. Presentation ! Container View UIView UIView UIViewController UIViewController
  • 37. Dismission ! Container View UIView UIView UIViewController UIViewController
  • 38. initialFrameForViewController finalFrameForViewController from to CGRectZero CGRectZero Presentation
  • 39. initialFrameForViewController finalFrameForViewController from CGRectZero to CGRectZero Dismissal
  • 40. viewWillDissapear ! viewDidDissapear FromViewController Presentation
  • 41. viewWillAppear ! viewDidAppear ToViewController Dismissal
  • 42. [transitionContext.containerView addSubview:toViewController.view]; ! toViewController.view.frame = CGRectInset([transitionContext initialFrameForViewController:fromViewController], 32.0f, 32.0f); ! toViewController.view.alpha = 0.0f; ! [UIView animateWithDuration:self.duration delay:0.0 options:0 animations:^{ toViewController.view.alpha = 1.0f; } completion:^(BOOL finished) { [transitionContext completeTransition:YES]; }]; Presentation
  • 43. [UIView animateWithDuration:self.duration delay:0.0 options:0 animations:^{ fromViewController.view.alpha = 0.0f; } completion:^(BOOL finished) { [transitionContext completeTransition:YES]; }]; Dismissal
  • 44. Interactive Transitions
  • 45. start complete
  • 46. start complete cancel finish updating
  • 47. Demo
  • 48. UIViewController UIViewController id <UIViewControllerTransitioningDelegate> transitioningDelegate animationControllerForPresentedController… animationControllerForDismissedController id <UIViewControllerAnimatedTransitioning> id <UIViewControllerAnimatedTransitioning> present dismiss
  • 49. @protocol UIViewControllerTransitioningDelegate <NSObject> ! @optional ! ! - (id <UIViewControllerAnimatedTransitioning>) animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController: (UIViewController *)source; ! ! - (id <UIViewControllerAnimatedTransitioning>) animationControllerForDismissedController:(UIViewController *)dismissed; ! ! - (id <UIViewControllerInteractiveTransitioning>)interactionControllerForPresentation:(id <UIViewControllerAnimatedTransitioning>)animator; ! ! - (id <UIViewControllerInteractiveTransitioning>)interactionControllerForDismissal: (id <UIViewControllerAnimatedTransitioning>)animator; ! ! @end
  • 50. @protocol UIViewControllerTransitioningDelegate <NSObject> ! @optional ! ! - (id <UIViewControllerAnimatedTransitioning>) animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController: (UIViewController *)source; ! ! - (id <UIViewControllerAnimatedTransitioning>) animationControllerForDismissedController:(UIViewController *)dismissed; ! ! - (id <UIViewControllerInteractiveTransitioning>)interactionControllerForPresentation:(id <UIViewControllerAnimatedTransitioning>)animator; ! ! - (id <UIViewControllerInteractiveTransitioning>)interactionControllerForDismissal: (id <UIViewControllerAnimatedTransitioning>)animator; ! ! @end
  • 51. UIViewController UIViewController id <UIViewControllerTransitioningDelegate> transitioningDelegate animationControllerForPresentedController… animationControllerForDismissedController id <UIViewControllerAnimatedTransitioning> id <UIViewControllerAnimatedTransitioning> present dismiss
  • 52. UIViewController UIViewController id <UIViewControllerTransitioningDelegate> transitioningDelegate id <UIViewControllerAnimatedTransitioning> id <UIViewControllerAnimatedTransitioning> present dismiss id <UIViewControllerInteractiveTra nsitioning> id <UIViewControllerInteractiveTra nsitioning>
  • 53. id <UIViewControllerInteractiveTransitioning>
  • 54. @protocol UIViewControllerInteractiveTransitioning <NSObject> ! - (void)startInteractiveTransition:(id <UIViewControllerContextTransitioning>)transitionContext; ! @optional ! - (CGFloat)completionSpeed; - (UIViewAnimationCurve)completionCurve; ! @end
  • 55. UIPercentDrivenInteractiveTransition
  • 56. UIPercentDrivenInteractiveTransition - (void)updateInteractiveTransition:(CGFloat)percentComplete; - (void)cancelInteractiveTransition; - (void)finishInteractiveTransition;
  • 57. CGFloat scale = [gestureRecognizer scale]; switch ([gestureRecognizer state]) { case UIGestureRecognizerStateBegan: transitionController.interactive = YES; _startScale = scale; [testViewController dismissViewControllerAnimated:YES completion:nil]; } break; case UIGestureRecognizerStateChanged: { CGFloat percent = (1.0 - scale/_startScale); [transitionController.percentDrivenInteractiveTransition updateInteractiveTransition: (percent <= 0.0) ? 0.0 : percent]; break; } case UIGestureRecognizerStateEnded: case UIGestureRecognizerStateCancelled: if ([gestureRecognizer velocity] >= 0.0 || [gestureRecognizer state] == UIGestureRecognizerStateCancelled) { [transitionController.percentDrivenInteractiveTransition cancelInteractiveTransition]; } else { [transitionController.percentDrivenInteractiveTransition finishInteractiveTransition]; } break; default: break; }
  • 58. CGFloat scale = [gestureRecognizer scale]; switch ([gestureRecognizer state]) { case UIGestureRecognizerStateBegan: transitionController.interactive = YES; _startScale = scale; [testViewController dismissViewControllerAnimated:YES completion:nil]; } break; case UIGestureRecognizerStateChanged: { CGFloat percent = (1.0 - scale/_startScale); [transitionController.percentDrivenInteractiveTransition updateInteractiveTransition: (percent <= 0.0) ? 0.0 : percent]; break; } case UIGestureRecognizerStateEnded: case UIGestureRecognizerStateCancelled: if ([gestureRecognizer velocity] >= 0.0 || [gestureRecognizer state] == UIGestureRecognizerStateCancelled) { [transitionController.percentDrivenInteractiveTransition cancelInteractiveTransition]; } else { [transitionController.percentDrivenInteractiveTransition finishInteractiveTransition]; } break; default: break; }
  • 59. Core Animation! ! +[UIView transitionFromView:toView:duration:options:completion:]! ! Custom Animations! ! UIView block-based animations UIPercentDrivenInteractiveTransition
  • 60. [UIView animateWithDuration:self.duration delay:0.0 options:0 animations:^{ toViewController.view.alpha = 1.0f; } completion:^(BOOL finished) { [fromViewController.view removeFromSuperview]; [transitionContext completeTransition:YES]; }];
  • 61. [UIView animateWithDuration:self.duration delay:0.0 options:0 animations:^{ toViewController.view.alpha = 1.0f; } completion:^(BOOL finished) { [fromViewController.view removeFromSuperview]; [transitionContext completeTransition: !transitionContext.transitionWasCancelled]; }];
  • 62. - (void)startInteractiveTransition:(id <UIViewControllerContextTransitioning>)transitionContext { ! _transitionContext = transitionContext; _toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey]; _toViewController.view.alpha = 0.0f; _toViewController.view.frame = [transitionContext finalFrameForViewController:_toViewController]; [transitionContext.containerView addSubview:_toViewController.view]; } id <UIViewControllerInteractiveTransitioning>
  • 63. id <UIViewControllerInteractiveTransitioning> - (void)updateInteractiveTransition:(CGFloat)percentComplete { _toViewController.view.alpha = percentComplete; [_transitionContext updateInteractiveTransition:percentComplete]; }
  • 64. id <UIViewControllerInteractiveTransitioning> - (void)cancelInteractiveTransition { [_transitionContext cancelInteractiveTransition]; [UIView animateWithDuration:0.3 delay:0.0 options:0 animations:^{ _toViewController.view.alpha = 0.0f; } completion:^(BOOL finished) { [_transitionContext completeTransition:! _transitionContext.transitionWasCancelled]; }]; }
  • 65. viewWillAppear viewDidAppear viewWillDisappear viewDidDisappear
  • 66. viewWillAppear viewDidAppear viewWillDisappear viewDidDisappear
  • 67. viewWillAppear viewWillDisappear viewDidDisappear
  • 68. - (void)viewWillAppear:(BOOL)animated { [self doSomeSideEffectsAssumingViewDidAppearIsGoingToBeCalled]; id <UIViewControllerTransitionCoordinator> coordinator; coordinator = [self transitionCoordinator]; if(coordinator && [coordinator initiallyInteractive]) { [transitionCoordinator notifyWhenInteractionEndsUsingBlock: ^(id <UIViewControllerTransitionCoordinatorContext> ctx) { if(ctx.isCancelled) { [self undoSideEffects]; } }]; } } UIViewControllerTransitionCoordinator
  • 69. UINavigationController – pushViewController:animated: – popViewControllerAnimated: – popToRootViewControllerAnimated: – popToViewController:animated:
  • 70. - (id<UIViewControllerAnimatedTransitioning>)! navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC ! toViewController:(UIViewController *)toVC UINavigationControllerDelegate - (id<UIViewControllerInteractiveTransitioning>)! navigationController:(UINavigationController *)navigationController interactionControllerForAnimationController: (id<UIViewControllerAnimatedTransitioning>)animationController
  • 71. UINavigationController @property(nonatomic, readonly) UIGestureRecognizer *interactivePopGestureRecognizer
  • 72. UITabBarController @property(nonatomic, assign) UIViewController *selectedViewController @property(nonatomic) NSUInteger selectedIndex
  • 73. UITabBarControllerDelegate - (id <UIViewControllerInteractiveTransitioning>)tabBarController:(UITabBarController *)tabBarController interactionControllerForAnimationController:(id <UIViewControllerAnimatedTransitioning>)animationController; ! - (id <UIViewControllerAnimatedTransitioning>)tabBarController:(UITabBarController *)tabBarController animationControllerForTransitionFromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC;
  • 74. finty fň
  • 75. // Snapshot UIView *fromView = [fromViewController.view snapshotViewAfterScreenUpdates:NO]; ! // Interactivity fromViewController.view.userInteractionEnabled = NO; toViewController.view.userInteractionEnabled = YES; transitionContext.containerView.userInteractionEnabled = YES; ! [transitionContext.containerView addSubview:fromView]; [transitionContext.containerView addSubview:toViewController.view]; ! // Finish before animation [transitionContext completeTransition:YES]; ! [UIView animateWithDuration: . . .
  • 76. // Prepare BitmapContext CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); GLubyte *textureData = malloc(textureWidth * textureHeight * 4); memset_pattern4(textureData, "0000", textureWidth * textureHeight * 4); NSUInteger bytesPerPixel = 4; NSUInteger bytesPerRow = bytesPerPixel * textureWidth; NSUInteger bitsPerComponent = 8; CGContextRef bitmapContext = CGBitmapContextCreate(textureData, textureWidth, textureHeight, bitsPerComponent, bytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big); CGColorSpaceRelease(colorSpace); // draw [view.layer renderInContext:bitmapContext]; CGContextRelease(bitmapContext); ! // set data for texture glBindTexture(GL_TEXTURE_2D, texture); // set bitmap data into texture glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, textureWidth, textureHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, textureData); // Don't need this data anymore free(textureData);
  • 77. fuck off view controllers
  • 78. Custom UIViewController Transitions Ján Ilavský - @split82