Draggable view controller? Interactive view controller!

Update

This post is aiming at the topic of UIViewController transitions. The gif shows what we are going to do — present ViewController from ViewController by dragging.

What is it?

To be short, you can't actually drag a UIViewController to anywhere.
What makes you feel UIViewController animate from here to there is UIViewControllerAnimatedTransitioning, interact with it according to gestures turns out to be misleading.

How to do it

Design philosophy

There is no two UIViewController in together, instead there's only one UIViewController at a time. When user begin drag on certain subview, present another view controller with custom UIViewControllerAnimatedTransitioning by custom UIPercentDrivenInteractiveTransition protocol.

Technical things

These two protocols are the foundation of customizing interactive UIViewController transitions. In case you don't know yet, take a glance before starting.
1. UIViewControllerAnimatedTransitioning protocol
2. UIPercentDrivenInteractiveTransition protocol

Your UIViewController implements UIViewControllerTransitioningDelegate protocol to tell which animator and interactor are gonna used by custom transitions.

Customize transitions

Animators

BaseAnimator

mustOverride() is a marco took from stackoverflow Yar's answer, or you can use nicklockwood's solution MustOverride GitHub. You can leave it blank as well, what mustOverride() does is throw an exception when we forget to override the method in subclasses.

BaseAnimator do only one thing, it determine if it's presenting or dismissing and call the corresponding method.

MiniToLargeViewAnimator

The trick is initialY property, as you can see, the UIViewController which transition customized will starts from initialY and ends at initialY as well. initialY is where our mini view located.

At the time user begin dragging, we present a new UIViewContrller and customize our transitionContext to make it looks like the same as last UIViewController.

- (UIView *)fakeMiniView returns fake subview from last UIViewController, you may either mock a new one or snapshot existing one, choosing a practice that fits with your use case.

Implement animators

Let's say we present NextViewController from ExistViewController.
In ExistViewController.m we declare class extension and implements UIViewControllerTransitioningDelegate.

ExistViewController

From now, you got a customized transitions animator, and sets up by UIViewControllerTransitioningDelegate.

present UIViewController

You should see your customized transition works.

Transitions response to gesture

MiniToLargeViewInteractive

attachToViewController:withView:presentViewController: is helper mehtod, encapsulate gesture bindings.

In ExistViewController, create two Interactors of presenting and dismissing, implement interactionControllerForPresentation: and interactionControllerForDismissal: methods from UIViewControllerTransitioningDelegate.

ExistViewController

There's a BOOL property disableInteractivePlayerTransitioning indicates if we want to skip custom UIPercentDrivenInteractiveTransition or not, if you want modal or dismiss ViewController directly, then set it to NO.

That's it.

Feel free to comment.

Update
comments powered by Disqus