Milad-Akarie / auto_route_library

Flutter route generator
MIT License
1.58k stars 400 forks source link

Auto Router Declarative do not trigger initial route transition animation #2001

Closed vladimir-boyko closed 2 months ago

vladimir-boyko commented 2 months ago

I stumbled to this problem recently while developing feature-flow with multiple pages.

I want to navigate to AutoRouter.declarative and set initial route conditionally. Sometimes first route will be bottom sheet page, sometimes regular full-screen page. Also I want AutoRouter page to be transparent (opaque: false) to be able to see previous page behind bottom sheet.

Problem: If I set any animations to the first declarative route in app_router.dart, it is ignored and shows default animation.

Also there is a problem when I'm dismissing my bottom sheet route and transparent auto router is still presents on the screen. Then I need to use gestures to close it

I want to understand what I'm doing wrong and be able to handle it.

Link to complete example - https://github.com/vladimir-boyko/test-auto-route

Here's my declarative router:

@RoutePage()
class ExampleDeclarativeRouter extends StatelessWidget {
  final bool isFirstRouteBottomSheet ;

  const ExampleDeclarativeRouter({
    super.key,
    required this.isFirstRouteBottomSheet,
  });

  @override
  Widget build(BuildContext context) {
    return AutoRouter.declarative(
      routes: (_) => [
        if (isFirstRouteBottomSheet)
          const BottomSheetPage()
        else
          const RegularPage()
      ],
    );
  }
}

App Router

@AutoRouterConfig(replaceInRouteName: 'Screen,Page',)
class AppRouter extends $AppRouter {
  @override
  RouteType get defaultRouteType => const RouteType.adaptive();

  @override
  final List<AutoRoute> routes = [
    AutoRoute(
      page: TopPage.page,
      path: '/top',
      initial: true,
    ),
    CustomRoute(
      page: ExampleDeclarativeRouter.page,
      path: '/declarative',
      opaque: false,
      children: [
        CustomModalBottomSheetRoute(
          page: BottomSheetPage.page,
          path: 'bottom_sheet',
        ),
        CustomRoute(
          page: RegularPage.page,
          path: 'regular',
          transitionsBuilder: TransitionsBuilders.slideTop,
        ),
      ],
    )
  ];
}

Top Screen

@RoutePage()
class TopScreen extends StatelessWidget {
  const TopScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          children: [
            const SizedBox(height: 200),
            const FlutterLogo(
              size: 200,
            ),
            TextButton(
              onPressed: () => context.pushRoute(
                ExampleDeclarativeRouter(isFirstRouteBottomSheet: true),
              ),
              child: const Text('Navigate to bottom sheet'),
            ),
            TextButton(
              onPressed: () => context.pushRoute(
                ExampleDeclarativeRouter(isFirstRouteBottomSheet: false),
              ),
              child: const Text('Navigate to regular'),
            ),
          ],
        ),
      ),
    );
  }
}

Regular Screen

@RoutePage()
class RegularScreen extends StatelessWidget {
  const RegularScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const Text('Second Screen'),
            TextButton(
              onPressed: context.router.maybePopTop,
              child: const Text('Pop Route'),
            ),
          ],
        ),
      ),
    );
  }
}

Bottom Sheet Screen

@RoutePage()
class BottomSheetScreen extends StatelessWidget {
  const BottomSheetScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const Text('First Screen'),
            TextButton(
              onPressed: () => context.router.maybePop(),
              child: const Text('Pop Route'),
            ),
          ],
        ),
      ),
    );
  }
}

CustomModalBottomSheetRoute

class CustomModalBottomSheetRoute<T> extends CustomRoute {
  CustomModalBottomSheetRoute({
    required PageInfo<T> super.page,
    super.path,
    super.guards,
    String? name,
  }) : super(
          customRouteBuilder: dialogRouteBuilder,
          transitionsBuilder: TransitionsBuilders.slideBottom,
        );

  static Route<T> dialogRouteBuilder<T>(
    BuildContext context,
    Widget child,
    AutoRoutePage<T> page,
  ) {
    return ModalBottomSheetRoute<T>(
      settings: page,
      useSafeArea: false,
      isScrollControlled: false,
      builder: (context) => child,
    );
  }
}
Milad-Akarie commented 2 months ago

not sure what's going on but I got two pointers for you, First, the navigator will skip animation for the very first route, Second, you're using a custom route with no transitions builder, by default CustomRoute has no transition

vladimir-boyko commented 2 months ago

@Milad-Akarie 1) It is not the very first route, it is the first route in declarative builder. 2) I applied transitions to child routes, it is where question lies, I want different transitions for different routes

Milad-Akarie commented 2 months ago

the first child of a sub-router will not be animated as well

vladimir-boyko commented 2 months ago

@Milad-Akarie Is it the intented behaviour, or is it a bug? And one more thing, if I add transition builder to AutoRouter.declarative, then transition will happen with the first child route, it is strange for me.

Milad-Akarie commented 2 months ago

it's actually intended, this by the done by stock Navigator, meaning it's not an auto_route thing, it will not look nice to animate the first route as the background will be blank.

vladimir-boyko commented 2 months ago

@Milad-Akarie Alright, is there a way to override this behaviour? At least how it can possibly be overrided

Milad-Akarie commented 2 months ago

@vladimir-boyko I'm really not sure, maybe take a dive into NavigatorState see what they're doing there.

I'm closing this for now, feel free to reopen if you there is any thing I can help you with.