Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Custom Transitions in iOS 7 - Cocoaheads Berlin...

Custom Transitions in iOS 7 - Cocoaheads Berlin Talk

Presented on 16.10.2013 in Cocoaheads Berlin

Engin Kurutepe

October 16, 2013
Tweet

Other Decks in Technology

Transcript

  1. Who? • Engin Kurutepe – @ekurutepe • iOS Team Lead

    at Txtr – www.txtr.com • Co-author of Developing an iOS 7 Edge http://bleedingedgepress.com/our-books/ developing-an-ios-7-edge/
  2. Roadmap • Which transitions can be customized? • Anatomy of

    a custom transition • A simple example • An interactive example
  3. Anatomy A lot of protocols: • UIViewControllerTransitioningDelegate • UIViewControllerInteractiveTransitioning •

    UIViewControllerAnimatedTransitioning • UIViewControllerTransitionCoordinator • UIViewControllerContextTransitioning • UIViewControllerTransitionCoordinatorContext
  4. in Practice… • Assign the transitioning delegate: • Full source

    code on Github: https://github.com/iosedgeapp/iOSEdge - (IBAction) presentTapped:(UIButton*)sender { BEPSimpleImageViewController* ivc = [[BEPSimpleImageViewController alloc] init]; ivc.image = [UIImage imageNamed:@"Canyon.jpg"]; ivc.modalPresentationStyle = UIModalPresentationCustom; ivc.transitioningDelegate = self; [self presentViewController:ivc animated:YES completion:nil]; }
  5. in Practice (cont’d) • Transitioning delegate vends an animator: -

    (id<UIVCAnimatedTransitioning>) animationControllerForPresentedController:(UIVC*)modal presentingController:(UIVC*)parent sourceController:(UIVC*)source { return [[BEPModalTransitionAnimator alloc] initWithDirection:BEPModelTransitionDirectionPresent]; }
  6. in Practice (cont’d) • Transitioning delegate does not vend an

    interaction controller // Not implemented: //- (id<UIViewControllerInteractiveTransitioning>) interactionControllerForPresentation: (id<UIViewControllerAnimatedTransitioning>)animator
  7. in Practice (cont’d) • The animator sets the duration for

    the transition - (NSTimeInterval) transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext { return 0.75; }
  8. in Practice (cont’d) • The animator performs the animations -

    (void) animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext { UIView* inView = [transitionContext containerView]; UIVC* fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey]; UIView* fromView = [fromVC view]; UIVC* toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey]; UIView* toView = [toVC view]; if (self.direction == BEPModelTransitionDirectionPresent) { [self performPresentationAnimations]; } else { [self performDismissalAnimations]; } }
  9. in Practice (cont’d) • The animator inserts the presented view

    • The animator MUST inform the context when transition is finished [inView insertSubview:toView aboveSubview:fromView]; [UIView animateWithDuration:[self transitionDuration:transitionContext] delay:0.0 usingSpringWithDamping:DampingConstant initialSpringVelocity:InitialVelocity options:0 animations:^{ toView.alpha = 1.0; toView.frame = finalRect; toView.transform = CGAffineTransformIdentity; } completion:^(BOOL finished) { [transitionContext completeTransition:YES]; }];
  10. How about interaction? • Transitioning Delegate must vend an interaction

    controller • Apple provides the UIPercentDrivenInteractiveTransition class • Can drive UIView block-based animations
  11. in Practice… • Transitioning Delegate vends an interaction controller: -

    (id <UIVCInteractiveTransitioning>) navigationController:(UINavigationController*)nc interactionControllerForAnimationController:(id<UIVCAnimatedTransitioning>)animator { if (animator == _popper && _popper.interactive) { return _popper; } else { return nil; } }
  12. in Practice (cont’d) • Previously during viewDidAppear… • but not

    interactive, no? self.popper = [[BEPNavigationTransitionsPopAnimator alloc] initWithNavigationController:self]; _popper.interactive = NO;
  13. in Practice (cont’d) • Previously during viewDidAppear… • but not

    interactive, no? self.popper = [[BEPNavigationTransitionsPopAnimator alloc] initWithNavigationController:self]; _popper.interactive = NO; - (instancetype) initWithNavigationController:(UINavigationController*)nc { if (self = [super init]) { self.parent = nc; UIPinchGestureRecognizer* pgr = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(handlePinch:)]; [self.parent.view addGestureRecognizer:pgr]; } return self; }
  14. in Practice (cont’d) • but still not interactive? - (void)

    handlePinch:(UIPinchGestureRecognizer*)gr { CGFloat scale = [gr scale]; switch ([gr state]) { case UIGestureRecognizerStateBegan: self.interactive = YES; _startScale = scale; [self.parent popViewControllerAnimated:YES]; break;
  15. in Practice (cont’d) • Popper driving the animation: case UIGestureRecognizerStateChanged:

    { CGFloat percent = (1.0 - scale/_startScale); [self updateInteractiveTransition:MAX(percent,0.0)]; break; } case UIGestureRecognizerStateEnded: case UIGestureRecognizerStateCancelled: if ([gr velocity] >= 0.0 || [gr state] == UIGestureRecognizerStateCancelled) { [self cancelInteractiveTransition]; } else { [self finishInteractiveTransition]; } self.interactive = NO; break; default: break; } }
  16. Re-cap • Custom transitions very powerful • Complex set of

    protocols • But in practice, it’s not that hard… • Source code for the examples available: https://github.com/iosedgeapp/iOSEdge
  17. Further Reading • WWDC 2013 Session 218 • objc.io article

    by Chris Eidhof http://www.objc.io/issue-5/view-controller- transitions.html • Developing an iOS 7 Edge (40% off for Cocoaheads): https://gumroad.com/ products/yLKx/cocoaheads