Repository: flutter
Issue: Support interactive transitions between routes (i.e., controlled by gesture)
Labels: framework,a: animation,f: routes,c: proposal,P3,team-framework,triaged-framework

## Use case

Transition from one route to another via transition. An example of this is the drag-to-pop gesture implemented by CupertinoPageRoute:
https://github.com/flutter/flutter/blob/master/packages/flutter/lib/src/cupertino/route.dart#L315

Implementing this involves a ton of boilerplate and is not intuitive. Since interactive transitions are a big part of mobile development (particularly on iOS), it seems that built-in framework support ought to be a priority.


## Proposal

There are many ways to implement this. One option would be to extend transitionBuilder() such that a gesture can intercept and drive the primary transition animation. Alternatively, a mixin can be provided to implement the boilerplate in such a way that the transition built by transitionBuilder() can be easily augmented to support a gesture.

It may also be possible to simply provide better documentation on how to build this with the existing tools. I've included my best attempt at describing the process, below.

## Suggested Documentation (Rough Draft)

* Hook into your route's transition (via buildTransitions) by wrapping the child with a custom gesture detector, as described in following steps.
   * Remember to disable the geture detector if (1) the primary animation is not completed or (2) the secondary animation is not dismissed or (4) anything else is happening that should inhibit the navigation gesture
   * This list may be incomplete
* Use a Listener and a Stack to capture pointer events, and feed these to a GestureRecognizer (addPointer
   * Open question: why a listener and not a GestureDetector?
* Delegate important events from the GestureRecognizer to a custom controller, converting to logical coordinates (gesture recognizers will report physical coordinates)
* The controller must have a reference to the transition's private animation controller (thus, you will also need to have subclassed a ModalRoute and not just used PageRouteBuilder)
* The controller must invoke NavigatorState.didStartUserGesture() so the Navigator can prepare the route below
* On gesture updates, tweak the animation.value in proportion to the gesture (this corresponds to the underlying TransitionRoute's AnimationController). This is safe because we ensured that no animation is currently playing in the first step.
* On gesture complete, determine whether the gesture succeeded or failed (e.g., for a drag, if the drag crossed the midpoint or exceeded a certain upward velocity, succeed; else, fail)
   * Animate forward or back. In either case, you should invoke Navigator.push() or Navigator.pop().
   * Remember that push() and pop() will trigger the transition animation to play via .forward() or .reverse()
   * You can specify a different curve / target using animateTo or animateBack (it's okay to interrupt the animation, as long as you confirm it's playing and not done via isAnimating())
* When the animation completes (note: it can complete instantly, if everything was gesture'd into the correct position, so use isAnimating() to check) you must invoke didStopUserGesture()