Flutter 使页面退出过渡动态/可变

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

我可以找到的关于颤动页面转换的所有资源都涉及在创建页面时定义页面的退出转换,但我希望我的页面根据用户导航到下一个页面而从屏幕左侧退出或从屏幕右侧退出。

我有三个屏幕,我希望它们水平滑动,就像它们排成一行一样 - 我正在使用底部导航栏,所以我希望它们水平滑动并相互推出,但默认过渡有它们堆叠在上一个屏幕的顶部并从底部滑入。

需要明确的是,当用户在中间页面点击当前选项卡右侧的选项卡时,我希望当前页面从左侧退出,新页面从右侧进入;如果用户单击左侧的选项卡,我希望当前页面从右侧退出,新页面从左侧进入。这意味着中间页面可以向左或向右退出,具体取决于下一页是什么。

我有以下代码,它可以正确执行入口转换,但退出转换是根据页面导航到的方式设置的,而不是根据页面导航离开的方式设置的。

Route routeSlideIn(Widget destinationPage, int direction) {
  return PageRouteBuilder(
    pageBuilder: (context, animation, secondaryAnimation) => destinationPage,
    transitionsBuilder: (context, animation, secondaryAnimation, child) {
      const curve = Curves.ease;
      final curveIn = CurvedAnimation(
        parent: animation,
        curve: curve,
      );
      final curveOut = CurvedAnimation(
          parent: secondaryAnimation,
          curve: curve
      );

      if (direction > 0) {
        final tweenIn = Tween(begin: Offset(1, 0), end: Offset.zero);
        final tweenOut = Tween(begin: Offset.zero, end: Offset(-1, 0));

        return SlideTransition(
          position: tweenIn.animate(curveIn),
          child: SlideTransition(
              position: tweenOut.animate(curveOut),
              child: child
          ),
        );
      } else {
        final tweenIn = Tween(begin: Offset(-1, 0), end: Offset.zero);
        final tweenOut = Tween(begin: Offset.zero, end: Offset(1, 0));

        return SlideTransition(
          position: tweenIn.animate(curveIn),
          child: SlideTransition(
              position: tweenOut.animate(curveOut),
              child: child
          ),
        );
      }

    },

  );
}

在具有底部导航栏的页面的嵌套导航器中调用该函数,并使用

onGenerateRoute: (settings) {
            var direction = 1;
            if (settings.arguments != null) {
              direction = (settings.arguments as StudentRouterArgs).direction;
            }

            late Widget page;
            switch (settings.name) {
              case null:
              case "/":
              case FirstPage.routeName:
                page = FirstPage();
                break;
              case SecondPage.routeName:
                page = SecondPage();
                break;
              case ThirdPage.routeName:
                page = ThirdPage();
                break;
              default:
                throw Exception('Unknown route: ${settings.name}');
            }

            return routeSlideIn(page, direction);
          },

然后更改路线:

_navigatorKey.currentState!.pushReplacementNamed(
              destination,
              arguments: StudentRouterArgs(index - oldIndex)
          );

我发现幻灯片转换类可以有一个 Listener 对象,但我以前从未使用过 Listener 对象,所以我不确定这是否是一个有效的解决方案,或者我什至将如何使用它。理想情况下,如果 PageRouteBuilder 可以为要替换的页面定义退出动画,而不是为即将进入的页面定义退出动画,那就太好了,但我不确定这是否可能。

实现这种可变退出转换的最佳方法是什么?

flutter flutter-animation
1个回答
0
投票

我为此目的开发了 cooperative_page_route 包。在你的情况下它的用法看起来像这样:

  1. CoordinatedRouteObserver
    添加到父导航器中的观察者列表中:
Navigator(
        observers: 
        [
          CoordinatedRouteObserver() // <--- This must go here!
        ],
        initialRoute: '/',
        onGenerateRoute: (settings) {  },
      ));
  1. 在您的
    onGenerateRoute
    中,您只需检查方向并推动适当的路线:
onGenerateRoute: (settings) {
            var direction = 1;
            if (settings.arguments != null) {
              direction = (settings.arguments as StudentRouterArgs).direction;
            }

            late Widget page;
            switch (settings.name) {
              case null:
              case "/":
              case FirstPage.routeName:
                page = FirstPage();
                break;
              case SecondPage.routeName:
                page = SecondPage();
                break;
              case ThirdPage.routeName:
                page = ThirdPage();
                break;
              default:
                throw Exception('Unknown route: ${settings.name}');
            }

            if (direction > 0) return ForwardPushRoute((context) => page);
            else if (direction < 0) return BackwardPushRoute((context) => page);
            else {
              // Its up to you how to handle this case (throw an exception, push a "neutral" route, push an "error" route, or something else)
            }
          },

上一页现在应该向适当的方向滑出。

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