flutter / flutter

Flutter makes it easy and fast to build beautiful apps for mobile and beyond
https://flutter.dev
BSD 3-Clause "New" or "Revised" License
164.96k stars 27.18k forks source link

[go_router] Missing exit animation support #122954

Open SaadArdati opened 1 year ago

SaadArdati commented 1 year ago

With the normal Navigator, you can provide a custom Route object when you run Navigator.push in order to provide custom animations.

  @optionalTypeArgs
  static Future<T?> push<T extends Object?>(BuildContext context, Route<T> route) {
    return Navigator.of(context).push(route);
  }

The reason this is important is because it allows you to specify an exit transition of the underlying page that is being moved away from.

Here is a thread explaining the desired effect. https://stackoverflow.com/questions/52762069/flutter-transition-exit

With GoRouter, this feature is partially missing.

        GoRoute(
          path: '/home',
          pageBuilder: (context, state) {
            return CustomTransitionPage(
              key: state.pageKey,
              child: const Home(),
              opaque: false,
              transitionsBuilder:
                  (context, animation, secondaryAnimation, child) {
                return defaultPageTransition(
                  context,
                  animation,
                  child,
                  reverse: true,
                );
              },
            );
          },
        ),

context.go('/')

There is currently no support go function that can consume an optional Route to handle exit transitions.

The CustomTransitionPage even provides the secondaryAnimation, mimicing the Navigator's exact behavior. It's simply unused.

I propose an exitTransitionBuilder in the constructor of CustomTransitionPage or support for a custom Route as an optional parameter in GoRouter.of(context).go('/', ....)

This is a very important missing feature from this package. I am currently unable to create fancier transition animations, and packages Flutter's own animations package https://pub.dev/packages/animations which heavily utilizes exit animations can not replicate their transitions with GoRouter.

SaadArdati commented 1 year ago

An alternative solution would be providing more information about the state inside the pageBuilder. At the current moment, you can have your secondary animation there, but you have zero information about the state of the navigation at time of flight.

IE: If I want my home page to slide left for a settings menu, but want my home page to slide up from the chat menu, this is impossible because the pageBuilder provides no information about what just happened.

SaadArdati commented 1 year ago

One workaround that has a bug is the following:

        leading: IconButton(
          tooltip: 'Settings',
          icon: const Icon(Icons.settings),
          onPressed: () {
            context.go('/settings', extra: {'from': '/home'});
          },
        ),

Then, in your pageBuilder, you do this:

          GoRoute(
            path: '/home',
            builder: (context, state) => const HomeScreen(),
            pageBuilder: (context, state) {
              final extra = state.extra;
              AxisDirection comesFrom = AxisDirection.down;
              print('Home State: ${state} | extra: ${state.extra}');
              if (extra != null && extra is Map) {
                final String? fromParam = extra['from'];
                if (fromParam == '/chat') {
                  comesFrom = AxisDirection.up;
                }
                extra.clear();
              }

              return CustomTransitionPage(
                key: state.pageKey,
                child: const HomeScreen(),
                opaque: false,
                transitionsBuilder:
                    (context, animation, secondaryAnimation, child) {
                  return defaultPageTransition(
                    context,
                    animation,
                    secondaryAnimation,
                    child,
                    state: state,
                    comesFrom: comesFrom,
                  );
                },
              );
            },
          ),

This is not good. And for some reason, the first time the transition happens, the extra map is ALWAYS null.

First time page transition: Home State: Instance of 'GoRouterState' | extra: null Second time same page transition: Home State: Instance of 'GoRouterState' | extra: null

johnpryan commented 1 year ago

Can you explain why you aren't using secondaryAnimation in your example? The behavior for transition animations should work the same as the Navigator API.

SaadArdati commented 1 year ago

@johnpryan

Can you explain why you aren't using secondaryAnimation in your example? The behavior for transition animations should work the same as the Navigator API.

Because I need some transitions to change depending on the context they are coming from. For example, if I have a main page and I click on the settings button, the settings page slides from left to center, the main page slides from center to right. The reverse happens when I go back to the main page. This is fine so far.

But if I click a card in the main page, and it opens a chat page by sliding from bottom to the center, I want the main page to slide from center to top. The reverse SHOULD happen when I go back to the main page. This is currently impossible because the secondary animation for the main page is center-to-right. I would need context as to what happened to the last page to know how to animate it back in.

The Navigator API solves this by allowing you to specify the transition directly inside of the Navigator.push function since it is the most specific you can get. GoRouter is missing this or something that can produce similar results.

As a hack, I used the extras object to track what page is coming from where, but it is imperfect and breaks on the first-transition of each page.

chunhtai commented 1 year ago

You should use a different route for different page that has different animation.

github-actions[bot] commented 1 year ago

Without additional information, we are unfortunately not sure how to resolve this issue. We are therefore reluctantly going to close this bug for now. If you find this problem please file a new issue with the same description, what happens, logs and the output of 'flutter doctor -v'. All system setups can be slightly different so it's always better to open new issues and reference the related ones. Thanks for your contribution.

SaadArdati commented 1 year ago

You should use a different route for different page that has different animation.

How would you currently use GoRouter to create a page transition for a given page that changes depending on which page it came from?

Note that GoRouterState does not provide information about the previous page/route.

npateras commented 3 months ago

I also currently stumbled upon this problem.

nateshmbhat commented 2 months ago

any rough guess on when can we expect this fix ?