Flutter Transition Exit

我的未来我决定 提交于 2019-11-28 12:47:09

Good question , the PageRouteBuilder use an AnimationController by default to handle the animation transition so, when you dismiss your view, it just call 'reverse' method from the animationController and you will see the same animation you are using but in reverse.

In case you want to change the animation when you dismiss your view you can do it checking the status of the current animation and compare with AnimationStatus.reverse

This is your code with a Fade animation when it's in reverse.

  class SlideLeftRoute extends PageRouteBuilder {
    final Widget enterWidget;
    SlideLeftRoute({this.enterWidget})
        : super(
            pageBuilder: (BuildContext context, Animation<double> animation,
                Animation<double> secondaryAnimation) {
              return enterWidget;
            },
            transitionsBuilder: (BuildContext context,
                Animation<double> animation,
                Animation<double> secondaryAnimation,
                Widget child) {
              if (animation.status == AnimationStatus.reverse) {
                //do your dismiss animation here
                return FadeTransition(
                  opacity: animation,
                  child: child,
                );
              } else {
                return SlideTransition(
                    position: new Tween<Offset>(
                      begin: const Offset(1.0, 0.0),
                      end: Offset.zero,
                    ).animate(animation),
                    child: child);
              }
            },
          );
  }

WORKAROUND

    class SlideLeftRoute extends PageRouteBuilder {
      final Widget enterWidget;
      final Widget oldWidget;

      SlideLeftRoute({this.enterWidget, this.oldWidget})
          : super(
                transitionDuration: Duration(milliseconds: 600),
                pageBuilder: (BuildContext context, Animation<double> animation,
                    Animation<double> secondaryAnimation) {
                  return enterWidget;
                },
                transitionsBuilder: (BuildContext context,
                    Animation<double> animation,
                    Animation<double> secondaryAnimation,
                    Widget child) {
                  return Stack(
                    children: <Widget>[
                      SlideTransition(
                          position: new Tween<Offset>(
                            begin: const Offset(0.0, 0.0),
                            end: const Offset(-1.0, 0.0),
                          ).animate(animation),
                          child: oldWidget),
                      SlideTransition(
                          position: new Tween<Offset>(
                            begin: const Offset(1.0, 0.0),
                            end: Offset.zero,
                          ).animate(animation),
                          child: enterWidget)
                    ],
                  );
                });
    }

Usage:

 Navigator.of(context)
              .push(SlideLeftRoute(enterWidget: Page2(), oldWidget: this));

I used a different way, but similar logic provided by diegodeveloper

Screenshot:

Complete code:

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Page1(),
    );
  }
}

class Page1 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Page 1"),
        leading: Icon(Icons.menu),
      ),
      body: Container(
        color: Colors.grey,
        child: Center(
          child: RaisedButton(
            onPressed: () => Navigator.push(context, MyCustomPageRoute(previousPage: this, builder: (context) => Page2())),
            child: Text("2nd Page"),
          ),
        ),
      ),
    );
  }
}

class Page2 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("Page 2")),
      body: Container(
        color: Colors.blueGrey,
        child: Center(
          child: RaisedButton(
            onPressed: () => Navigator.pop(context),
            child: Text("Back"),
          ),
        ),
      ),
    );
  }
}

class MyCustomPageRoute extends MaterialPageRoute {
  final Widget previousPage;
  MyCustomPageRoute({this.previousPage, WidgetBuilder builder, RouteSettings settings}) : super(builder: builder, settings: settings);

  @override
  Widget buildTransitions(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation, Widget currentPage) {
    Animation<Offset> _slideAnimationPage1 = Tween<Offset>(begin: Offset(0.0, 0.0), end: Offset(-1.0, 0.0)).animate(animation);
    Animation<Offset> _slideAnimationPage2 = Tween<Offset>(begin: Offset(1.0, 0.0), end: Offset(0.0, 0.0)).animate(animation);
    return Stack(
      children: <Widget>[
        SlideTransition(position: _slideAnimationPage1, child: previousPage),
        SlideTransition(position: _slideAnimationPage2, child: currentPage),
      ],
    );
  }
}

There is another way to do it. The problem of initState() getting called in oldWidget won't be there anymore.

void main() => runApp(MaterialApp(theme: ThemeData.dark(), home: HomePage()));

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("Page 1")),
      body: RaisedButton(
        child: Text("Next"),
        onPressed: () {
          Navigator.push(
            context,
            PageRouteBuilder(
              pageBuilder: (c, a1, a2) => Page2(),
              transitionsBuilder: (context, anim1, anim2, child) {
                return SlideTransition(
                  position: Tween<Offset>(end: Offset(0, 0), begin: Offset(1, 0)).animate(anim1),
                  child: Page2(),
                );
              },
            ),
          );
        },
      ),
    );
  }
}

class Page2 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("Page 2")),
      body: RaisedButton(
        child: Text("Back"),
        onPressed: () => Navigator.pop(context),
      ),
    );
  }
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!