title: Widgets sliding from outside the screen in Flutter ? Similar to Android 8 app drawer
body: <p>I am writing a flashcard app (an extension to the open source AnkiDroid app) in Flutter. The basic workflow is: the app shows me a question and I can reveal the answer. The gesture I want in order to reveal the answer is similar to the Android 8 swipe up from the bottom icon row to reveal the app drawer. A fast swipe (or fling in the android terminology?) can reveal the app list, but a drawn out, slow swipe can control the motion of the apps drawer.</p>
  
  <p>My questions are the following:</p>
  
  <ul>
  <li>What is the proper way to have widgets slide in from outside the screen ? Flutter complains that I'm trying to display widgets outside the screen, suggests I use ClipRect, but I haven't found a way for ClipRect to only display something the size of the screen (it seems to adjust itself to the size of the child)</li>
  <li>What is the recommended layout for what I want to do ? Currently I have the question and answer in a Column, and in order to center the question initially and hide the question, I modify the padding. It feels like a bit of a hack.</li>
  <li>Is there a helper library that can help me achieve the exact swipe/fling motion that I'm after? It needs to take into account momentum and position in order for the motion to feel just as natural as the android 8 app drawer.</li>
  </ul>
  
  <p>Thank you for any suggestions you may have.</p>
  
  <p>Here are the screens I have so far:</p>
  
  <p><strong>Question screen</strong></p>
  
  <p><a href="https://i.stack.imgur.com/hwIza.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/hwIza.png" alt="question screen"></a></p>
  
  <p><strong>Answer screen (after swiping up)</strong></p>
  
  <p><a href="https://i.stack.imgur.com/vGuOU.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/vGuOU.png" alt="answer screen"></a></p>
  
  <p>And here's the code:</p>
  
  <pre><code>import 'package:flutter/material.dart';
  import 'dart:math';
  // Uncomment lines 7 and 10 to view the visual layout at runtime.
  //import 'package:flutter/rendering.dart' show debugPaintSizeEnabled;
  
  void main() {
    //debugPaintSizeEnabled = true;
    runApp(MyApp());
  }
  
  /*
   * travel around the world
   * 環遊世界
   * wàan jàu sâi gâai
   */
  
  class Card extends StatefulWidget {
    @override
    createState() =&gt; CardState();
  }
  
  class CardState extends State&lt;Card&gt; with SingleTickerProviderStateMixin {
    var _dragStartOffset;
  
    Animation&lt;double&gt; questionAnimation;
    Animation&lt;double&gt; answerAnimation;
    Animation&lt;double&gt; opacityAnimation;
    AnimationController controller;
  
    initState() {
      super.initState();
      controller = AnimationController(duration: const Duration(milliseconds: 250), vsync: this);
      questionAnimation = Tween(begin: 250.0, end: 150.0).animate(controller)
        ..addListener(() {
          setState(() {
            // the state that has changed here is the animation object’s value
          });
        });
      answerAnimation = Tween(begin: 200.0, end: 32.0).animate(controller)
        ..addListener(() {
          setState(() {
            // the state that has changed here is the animation object’s value
          });
        });
      opacityAnimation = Tween(begin: 0.0, end: 1.0).animate(controller)
        ..addListener(() {
          setState(() {
            // the state that has changed here is the animation object’s value
          });
        });
  
    }
  
  
    @override
    Widget build(BuildContext context) {
      Widget question = Container(
          padding:  EdgeInsets.only(top: questionAnimation.value),
          child: Center (
              child: Text(
                "travel around the world",
                style: TextStyle(
                  fontWeight: FontWeight.bold,
                  fontSize: 48.0,
                ),
                textAlign: TextAlign.center,
              )
          ),
      );
  
      Widget answer = Container(
          padding:  EdgeInsets.only(top: answerAnimation.value),
          child: Opacity(
            opacity: opacityAnimation.value,
            child: Text(
                "wàan jàu sâi gâai 環遊世界",
                style: TextStyle(
                  fontWeight: FontWeight.bold,
                  fontSize: 48.0,
                ),
                textAlign: TextAlign.center,
              )
          )
      );
  
      var children = [question, answer];
  
      var child = GestureDetector(
          onTap: () {
              controller.reset();
          },
          onVerticalDragUpdate: (data) {
            // print(data);
            var currentOffset = data.globalPosition;
            var travel = _dragStartOffset - currentOffset;
            // print(travel);
  
            if(travel.dy &lt;0 )
            {
              return;
            }
  
            // cannot be lower than zero
            var travelY = max&lt;double&gt;(0.0, travel.dy);
            // cannot be higher than 100
            travelY = min&lt;double&gt;(200.0, travelY);
  
            var animationPosition = travelY / 200.0;
            controller.value = animationPosition;
          },
          onVerticalDragEnd: (data) {
            if(controller.value &gt; 0.50) {
              // make the animation continue on its own
              controller.forward();
            } else {
              // go back the other way
              controller.reverse();
            }
          },
          onVerticalDragStart: (data) {
            //print(data);
            _dragStartOffset = data.globalPosition;
          },
          child: Scaffold(
            appBar: AppBar(
              title: Text('AnkiReview'),
            ),
            body:  Container(
                child:Column(
                  children: children,
                )
            ),
          )
  
      );
  
  
      return child;
  
  
  
    }
  }
  
  class MyApp extends StatelessWidget {
    @override
    Widget build(BuildContext context) {
  
      return MaterialApp(
        title: 'Flutter Demo',
        home: Card(),
      );
    }
  }
  </code></pre>