Set default transition for go_router in Flutter
Asked Answered
A

7

17

as the docs from go_router describe, it is easy to set pageBuilder-Transitions for single pages. However, I want to set the default PageTransition for all pages.

How do I set the default page transition with/for go_router in Flutter?

Single Page:


  // this is the proposed method to do it for single pages
  // how can i apply it to all pages without writing the same code?
  GoRoute(
      path: '/login',
      builder: (context, state) => const LoginScreen(),
      pageBuilder: (context, state) => CustomTransitionPage<void>(
        key: state.pageKey,
        child: const LoginScreen(),
        transitionsBuilder: (context, animation, secondaryAnimation, child) =>
            FadeTransition(opacity: animation, child: child),
      ),
    ),

Best regards

Allan answered 27/3, 2022 at 12:40 Comment(0)
C
36

The go_router package does not support this at the moment, but to reduce code duplication, you can create a helper function that would apply the custom transition for your route, like:

CustomTransitionPage buildPageWithDefaultTransition<T>({
  required BuildContext context, 
  required GoRouterState state, 
  required Widget child,
}) {
  return CustomTransitionPage<T>(
    key: state.pageKey,
    child: child,
    transitionsBuilder: (context, animation, secondaryAnimation, child) => 
      FadeTransition(opacity: animation, child: child),
  );
}

<...>

GoRoute(
  path: '/login',
  pageBuilder: (context, state) => buildPageWithDefaultTransition<void>(
    context: context, 
    state: state, 
    child: LoginScreen(),
  ),
),
Clump answered 27/3, 2022 at 21:16 Comment(2)
It works. Upvoted. I wonder in an invocation of transitionBuilder, animation, and secondaryAnimation objects come from where?Acetal
nit: in the example, builder: (context, state) => const LoginScreen(), is no longer needed, I think?Burny
H
9

Why not use like this its way easier than the accepted answer

GoRoute TransitionGoRoute({
  required String path,
  required Widget Function(BuildContext, GoRouterState) pageBuilder,
}) {
  return GoRoute(
    path: path,
    pageBuilder: (context, state) => CustomTransitionPage<void>(
      key: state.pageKey,
      transitionDuration: const Duration(milliseconds: 300),
      child: pageBuilder(context, state),
      transitionsBuilder: (context, animation, secondaryAnimation, child) {
        return FadeTransition(
          opacity: CurveTween(curve: Curves.easeIn).animate(animation),
          child: child,
        );
      },
    ),
  );
}

then use like

    TransitionGoRoute(
      path: ScreenPaths.viewEmail,
      pageBuilder: (context, state) {
        final extra = state.extra;
        return ViewEmailScreen(
          email: extra as HiveEmail,
        );
      },
    ),
Heeled answered 5/8, 2023 at 1:1 Comment(0)
B
7

The more correct way is inheritance from CustomTransitionPage.

class WebPage extends CustomTransitionPage {
  WebPage({
    LocalKey key,
    ... // other properties taken from `MaterialPage`
    required Widget child
  }) : super(
         key: key,
         transitionBuilder: (...) {
           return FadeTransition(...);
         }
         child: child, // Here you may also wrap this child with some common designed widget
       );
}

Then

GoRoute(
  path: '/login',
  pageBuilder: (context, state) => WebPage(
    key: state.pageKey,
    child: const LoginScreen(),
  ),
),
Britt answered 12/5, 2022 at 16:16 Comment(2)
Look at the source of NoTransitionPage class in the go_router package (custom_transition_page.dart) for a full example of the implementation.Zigzag
Correct answer but not runnable. Check this answer for a compilable and working example of this answer. I also think GoRoute.builder needs to be removed.Jillene
Z
7

Expanding on @mkobuolys answer, the boilerplate can be reduced further, by returning function that creates page builder, i.e.:

CustomTransitionPage buildPageWithDefaultTransition<T>({
  required BuildContext context,
  required GoRouterState state,
  required Widget child,
}) {
  return CustomTransitionPage<T>(
    key: state.pageKey,
    child: child,
    transitionsBuilder: (context, animation, secondaryAnimation, child) =>
        FadeTransition(opacity: animation, child: child),
  );
}

Page<dynamic> Function(BuildContext, GoRouterState) defaultPageBuilder<T>(
        Widget child) =>
    (BuildContext context, GoRouterState state) {
      return buildPageWithDefaultTransition<T>(
        context: context,
        state: state,
        child: child,
      );
    };

and the router would look like:

final _router = GoRouter(
  routes: [
    GoRoute(
      path: '/a',
      builder: (context, state) => const PageA(),
      pageBuilder: defaultPageBuilder(const PageA()),
    ),
    GoRoute(
      path: '/b',
      builder: (context, state) => const PageB(),
      pageBuilder: defaultPageBuilder(const PageB()),
    ),
  ],
);
Zoan answered 8/4, 2023 at 20:42 Comment(1)
I like this implementation. How would you work with params or query params on the pageBuilder?Floribunda
A
4

Below is a code for the transition factory (heavily based on the answer of @mkobuolys). It adds 3 more transition effects: scale, rotation, and size.

Rotation for my taste makes too many turns, size looks like there is almost no transition effect, but scale is kinda fine.

import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';

class RouterTransitionFactory {
 static CustomTransitionPage getTransitionPage(
  {required BuildContext context,
  required GoRouterState state,
  required Widget child,
  required String type}) {
 return CustomTransitionPage(
    key: state.pageKey,
    child: child,
    transitionsBuilder: (context, animation, secondaryAnimation, child) {
      switch (type) {
        case 'fade':
          return FadeTransition(opacity: animation, child: child);
        case 'rotation':
          return RotationTransition(turns: animation, child: child);
        case 'size':
          return SizeTransition(sizeFactor: animation, child: child);
        case 'scale':
          return ScaleTransition(scale: animation, child: child);
        default:
          return FadeTransition(opacity: animation, child: child);
      }
    });
  }
}

Should be called like this:

GoRoute(
    path: '/settings',
    builder: (context, state) => const Settings(), //StatelessWidget
    pageBuilder: (context, state) => RouterTransitionFactory.getTransitionPage(
      context: context,
      state: state,
      child: const Settings(), 
      type: 'scale', // fade|rotation|scale|size
    ),
  ),
Acetal answered 27/3, 2023 at 15:4 Comment(0)
C
4

This may be newer than these answers but the transition can be done in the theme rather than in the router code.

https://api.flutter.dev/flutter/material/PageTransitionsTheme-class.html

From that page:

   Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(
        useMaterial3: true,
        // Defines the page transition animations used by MaterialPageRoute
        // for different target platforms.
        // Non-specified target platforms will default to
        // ZoomPageTransitionsBuilder().
        pageTransitionsTheme: const PageTransitionsTheme(
          builders: <TargetPlatform, PageTransitionsBuilder>{
            TargetPlatform.iOS: CupertinoPageTransitionsBuilder(),
            TargetPlatform.linux: OpenUpwardsPageTransitionsBuilder(),
            TargetPlatform.macOS: FadeUpwardsPageTransitionsBuilder(),
          },
        ),
      ),
      home: const HomePage(),
    );
  }
Chewy answered 8/4, 2024 at 14:24 Comment(0)
S
2

I did the following using go_router_builder and mixin.
I hope this idea is helpful to someone.

/// Route to [BrandDetailsPage]
@TypedGoRoute<BrandDetailsRoute>(path: '/brands/:brandId')
class BrandDetailsRoute extends GoRouteData with DefaultPageBuilder {
  const BrandDetailsRoute({
    required this.brandId,
  });

  final String brandId;

  @override
  Widget build(BuildContext context, GoRouterState state) => BrandDetailsPage(this);
}

mixin DefaultPageBuilder {
  Widget build(BuildContext context, GoRouterState state);

  Page<void> buildPage(BuildContext context, GoRouterState state) => pageOf(build(context, state));
}

CustomTransitionPage<T> pageOf<T>(Widget child) => CustomTransitionPage<T>(
      child: child,
      transitionDuration: Duration(milliseconds: 150),
      transitionsBuilder: (_0, animation, _1, child) => FadeTransition(opacity: animation, child: child),
    );
Semilunar answered 10/12, 2023 at 9:6 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.