Flutter Transition Exit

余生颓废 提交于 2019-12-28 06:55:25

问题


On Android API we can use

overridePendingTransition(int enterAnim, int exitAnim) 

to define the enter and exit transitions.

How to do it in Flutter?

I have implemented this code

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) {
        return SlideTransition(
          position: new Tween<Offset>(
            begin: const Offset(1.0, 0.0),
            end: Offset.zero,
          ).animate(animation),
          child: child
        );
      },

  );
}

but it only defines the enter transition. How can i define de exit transition?

UPDATE

Imagine that i have two screens (Screen1 and Screen2), when i execute

 Navigator.push(
        context, SlideLeftRoute(enterWidget: Screen2()));

i'd like to apply an animation to both Screen1 and Screen2 and not only to Screen2

example


回答1:


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));



回答2:


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),
      ],
    );
  }
}



回答3:


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),
      ),
    );
  }
}


来源:https://stackoverflow.com/questions/52762069/flutter-transition-exit

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!