flutter:动画过渡到命名路线

问题描述 投票:0回答:5

当我使用

Navigator.pushNamed(context, "/someRoute");
时,有一个最小的动画从屏幕底部在新路线中滑动(在Android上,在iOS上可能看起来不同)。

如何向此过渡添加自定义动画?

我找到了这篇文章,其中有一些非常简洁的未命名路线示例代码。他们实现了自己的类,该类继承自

PageRouteBuilder
并且可以像这样使用:
Navigator.push(context, SlideRightRoute(page: Screen2()))
。但
PageRouteBuilder
不是 Widget,不能在
MaterialApp
中注册为路线。所以我不知道如何将其应用于命名路由。

flutter flutter-animation
5个回答
67
投票

您需要在

onGenerateRoute
 小部件中使用 
MaterialApp

onGenerateRoute: (settings) {
  if (settings.name == "/someRoute") {
    return PageRouteBuilder(
      settings: settings, // Pass this to make popUntil(), pushNamedAndRemoveUntil(), works
      pageBuilder: (_, __, ___) => SomePage(),
      transitionsBuilder: (_, a, __, c) => FadeTransition(opacity: a, child: c)
    );
  }
  // Unknown route
  return MaterialPageRoute(builder: (_) => UnknownPage());
},

3
投票

我找到了一个简单的解决方案(灵感来自此代码

首先需要为MaterialApp设置一个静态的GlobalKey并导出

static GlobalKey mtAppKey = GlobalKey();

Widget build(BuildContext context) {
  return MaterialApp(
    key: MyApp.mtAppKey,
    ...

此外,您需要一个自定义的 PageRouteBuilder 来处理它

零安全禁用

class CustomNamedPageTransition extends PageRouteBuilder {
  CustomNamedPageTransition(
    GlobalKey materialAppKey,
    String routeName, {
    Object arguments,
  }) : super(
          settings: RouteSettings(
            arguments: arguments,
            name: routeName,
          ),
          pageBuilder: (
            BuildContext context,
            Animation<double> animation,
            Animation<double> secondaryAnimation,
          ) {
            assert(materialAppKey.currentWidget != null);
            assert(materialAppKey.currentWidget is MaterialApp);
            var mtapp = materialAppKey.currentWidget as MaterialApp;
            var routes = mtapp.routes;
            assert(routes.containsKey(routeName));
            return routes[routeName](context);
          },
          transitionsBuilder: (
            BuildContext context,
            Animation<double> animation,
            Animation<double> secondaryAnimation,
            Widget child,
          ) =>
              FadeTransition(
            opacity: animation,
            child: child,
          ),
          transitionDuration: Duration(seconds: 1),
        );
}

启用零安全

class CustomNamedPageTransition extends PageRouteBuilder {
  CustomNamedPageTransition(
    GlobalKey materialAppKey,
    String routeName, {
    Object? arguments,
  }) : super(
          settings: RouteSettings(
            arguments: arguments,
            name: routeName,
          ),
          pageBuilder: (
            BuildContext context,
            Animation<double> animation,
            Animation<double> secondaryAnimation,
          ) {
            assert(materialAppKey.currentWidget != null);
            assert(materialAppKey.currentWidget is MaterialApp);
            var mtapp = materialAppKey.currentWidget as MaterialApp;
            var routes = mtapp.routes;
            assert(routes!.containsKey(routeName));
            return routes![routeName]!(context);
          },
          transitionsBuilder: (
            BuildContext context,
            Animation<double> animation,
            Animation<double> secondaryAnimation,
            Widget child,
          ) =>
              FadeTransition(
            opacity: animation,
            child: child,
          ),
          transitionDuration: Duration(seconds: 1),
        );
}

然后,您可以使用

打开您的命名路线
Navigator.push(
  context,
  CustomNamedPageTransition(
    MyApp.mtAppKey,
    MyRoute.routeName,
  ),
);

Navigator.pushReplacement(
  context,
  CustomNamedPageTransition(
    MyApp.mtAppKey,
    MyRoute.routeName,
  ),
);

2
投票

无需

onGenerateRoute
即可使用动画路线!

如果您使用

MaterialApp
routes
映射来定义命名路由,以下是如何定义命名路由(其名称不会是
null
)。

只需通过扩展

PageRouteBuilder
来创建你的路线:

import 'package:flutter/material.dart';

class FadeInRoute extends PageRouteBuilder {
  final Widget page;

  FadeInRoute({this.page, String routeName})
      : super(
          settings: RouteSettings(name: routeName),            // set name here
          pageBuilder: (
            BuildContext context,
            Animation<double> animation,
            Animation<double> secondaryAnimation,
          ) =>
              page,
          transitionsBuilder: (
            BuildContext context,
            Animation<double> animation,
            Animation<double> secondaryAnimation,
            Widget child,
          ) =>
              FadeTransition(
            opacity: animation,
            child: child,
          ),
          transitionDuration: Duration(milliseconds: 500),
        );
}

然后当您导航时,只需执行以下操作:

Navigator.push( // or pushReplacement, if you need that
  context,
  FadeInRoute(
    routeName: RouteNames.home,
    page: MyHomeScreen(),
  ),
);

0
投票

创建动画过渡并使用

popUntil
和命名路线 不需要 需要使用
onGenerateRoute
。您只需在创建
routeName
时再次指定
PageRouteBuilder
即可。

修改 Flutter docs 中的示例,维护对路由的命名引用可以通过在

settings
中添加
PageRouteBuilder
参数来实现:

Route _createRoute() {
  return PageRouteBuilder(
    settings: RouteSettings(name: '/new-screen'),
    pageBuilder: (context, animation, _) => const NewScreen(),
    transitionsBuilder: (context, animation, _, child) {
      const begin = Offset(0.0, 1.0);
      const end = Offset.zero;
      const curve = Curves.ease;

      var tween = Tween(begin: begin, end: end).chain(CurveTween(curve: curve));

      return SlideTransition(
        position: animation.drive(tween),
        child: child,
      );
    },
  );
}

简单地使用

Navigator.of(context).push(_createRoute())
;

来调用

屏幕

NewScreen
可以在
MaterialApp
路线下正常注册:

 MaterialApp(
 ...
 ...
   routes: {
     ...
     '/new-screen': (context) => NewScreen(),
   }
 )

您可以修改上面的代码以使其更加动态。 也就是说,使用

onGeneratedRoute
是更永久的解决方案


0
投票

使用以下代码在 flutter 中为命名路线设置动画

首先构建过渡动画:

class SizeTransitionAnimation extends PageRouteBuilder {
final Widget page;
 SizeTransitionAnimation({required this.page})
  : super(
      pageBuilder: (context, animation, anotherAnimation) => page,
      transitionDuration: Duration(milliseconds: 1000),
      reverseTransitionDuration: Duration(milliseconds: 200),
      transitionsBuilder: (context, animation, anotherAnimation, child) {
        animation = CurvedAnimation(
            parent: animation,
            curve: Curves.fastLinearToSlowEaseIn,
            reverseCurve: Curves.fastOutSlowIn);
        return ScaleTransition(
          alignment: Alignment.center,
          scale: animation,
          child: child,
        );
      },
    );

}

对我来说,我使用 OnGenerateRoute 如下:

class RouteGenerator {
static Route<dynamic> generatedRoute(RouteSettings settings) {
switch (settings.name) {
  case MainScreen.routeName:
    return SizeTransitionAnimation(
      page: MainScreen(),
    );
  case ProductDetailsScreen.routeName:
    return SizeTransitionAnimation(
      page: ProductDetailsScreen(),
    );
  default:
    return _errorRoute();
}

}

© www.soinside.com 2019 - 2024. All rights reserved.