自定义路由切换动画

Material库中提供了一个MaterialPageRoute,它可以使用和平台风格一致的路由切换动画,如在iOS上会左右滑动切换,而在Android上会上下滑动切换。如果在Android上也想使用左右切换风格,可以直接使用CupertinoPageRoute, 如:

  1. Navigator.push(context, CupertinoPageRoute(
  2. builder: (context){
  3. return PageB(); //路由B
  4. }
  5. ));

如果想自定义路由切换动画,可以使用PageRouteBuilder,例如我们想以渐隐渐入动画来实现路由过渡:

  1. Navigator.push(context, PageRouteBuilder(
  2. transitionDuration: Duration(milliseconds: 500), //动画时间为500毫秒
  3. pageBuilder: (BuildContext context, Animation animation,
  4. Animation secondaryAnimation) {
  5. return new FadeTransition( //使用渐隐渐入过渡,
  6. opacity: animation,
  7. child: PageB(); //路由B
  8. );
  9. }));
  10. }),

我们可以看到pageBuilder 有一个animation参数,这是Flutter路由管理器提供的,在路由切换时pageBuilder在每个动画帧都会被回调,因此我们可以通过animation对象来自定义过渡动画。

无论是MaterialPageRoute、CupertinoPageRoute,还是PageRouteBuilder,它们都继承自PageRoute类,而PageRouteBuilder其实只是PageRoute的一个包装,我们可以直接继承PageRoute类来实现自定义路由,上面的例子可以通过如下方式实现:

  1. 定义一个路由类FadeRoute

    1. class FadeRoute extends PageRoute {
    2. FadeRoute({
    3. @required this.builder,
    4. this.transitionDuration = const Duration(milliseconds: 300),
    5. this.opaque = true,
    6. this.barrierDismissible = false,
    7. this.barrierColor,
    8. this.barrierLabel,
    9. this.maintainState = true,
    10. });
    11. final WidgetBuilder builder;
    12. @override
    13. final Duration transitionDuration;
    14. @override
    15. final bool opaque;
    16. @override
    17. final bool barrierDismissible;
    18. @override
    19. final Color barrierColor;
    20. @override
    21. final String barrierLabel;
    22. @override
    23. final bool maintainState;
    24. @override
    25. Widget buildPage(BuildContext context, Animation<double> animation,
    26. Animation<double> secondaryAnimation) => builder(context);
    27. @override
    28. Widget buildTransitions(BuildContext context, Animation<double> animation,
    29. Animation<double> secondaryAnimation, Widget child) {
    30. return FadeTransition(
    31. opacity: animation,
    32. child: builder(context),
    33. );
    34. }
    35. }
  2. 使用FadeRoute

    1. Navigator.push(context, FadeRoute(builder: (context) {
    2. return PageB();
    3. }));

虽然上面的两种方法都可以实现自定义切换动画,但实际使用时应考虑优先使用PageRouteBuilder,这样无需定义一个新的路由类,使用起来会比较方便。但是有些时候PageRouteBuilder是不能满足需求的,例如在应用过渡动画时我们需要读取当前路由的一些属性,这时就只能通过继承PageRoute的方式了,举个例子,假如我们只想在打开新路由时应用动画,而在返回时不使用动画,那么我们在构建过渡动画时就必须判断当前路由isActive属性是否为true,代码如下:

  1. @override
  2. Widget buildTransitions(BuildContext context, Animation<double> animation,
  3. Animation<double> secondaryAnimation, Widget child) {
  4. //当前路由被激活,是打开新路由
  5. if(isActive) {
  6. return FadeTransition(
  7. opacity: animation,
  8. child: builder(context),
  9. );
  10. }else{
  11. //是返回,则不应用过渡动画
  12. return Padding(padding: EdgeInsets.zero);
  13. }
  14. }

关于路由参数的详细信息读者可以自行查阅API文档,比较简单,不再赘述。