4

I'm using Navigator 2.0 API to handle navigation in my app, and I have problem with top-most RouterDelegate (the nested RouterDelegates underneath it work fine). Depending on authentication state I want to show Splash Screen, Login Screen, or Home Screen. The logic works fine and pages change depending on provided state, but there are no page transitions shown, neither on Android and iOS. That's weird, because in nested navigators this problem does not occurr. I've tried using several different Page classes, as well as changing page order in stack, but nothing seems to help - the transition animations seem to be completely ignored. Here's how my app structure looks like:

Main App definition:

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) => FutureBuilder(
        future: AppInit.initApp(),
        builder: (context, snapshot) {
          if (snapshot.hasError) {
            log(
              "App init failed!",
              level: Level.SEVERE.value,
              error: snapshot.error,
              stackTrace: snapshot.stackTrace,
            );
          }
          return _app();
        },
      );

  Widget _app() => MaterialApp(
        supportedLocales: LocalizationConfig.supportedLocales,
        localizationsDelegates: LocalizationConfig.localizationDelegates,
        theme: LightTheme().themeData,
        navigatorObservers: [
          FirebaseAnalyticsObserver(
            analytics: AppDependencies.firebaseAnalytics,
          )
        ],
        home: MultiRepositoryProvider(
          providers: AppRepositoryProviders.list,
          child: MultiBlocProvider(
            providers: AppBlocProviders.list,
            child: Router(
              routerDelegate: AppRouter(),
              backButtonDispatcher: RootBackButtonDispatcher(),
            ),
          ),
        ),
      );
}

Any my AppRouter page construction looks like this:

  @override
  Widget build(BuildContext context) => BlocBuilder<AppNavigationCubit, AppNavigationState>(
        builder: (context, state) => Navigator(
          key: internalNavigatorKey,
          onPopPage: (route, dynamic result) => _popPage(context, route, result),
          pages: getPageStack(context, state),
        ),
      );

  List<Page> getPageStack(BuildContext context, AppNavigationState state) {
    List<Page> pageStack = [];

    if (state is AppNavigationInitial) {
      pageStack.add(SlideTransitionPage<void>(
        key: AppRoutes.splash.valueKey,
        name: AppRoutes.splash.name,
        child: const SplashScreen(),
      ));
    }

    if (state is AppNavigationLoggedOut) {
      pageStack.add(SlideTransitionPage<void>(
        key: AppRoutes.auth.valueKey,
        name: AppRoutes.auth.name,
        child: const AuthScreen(),
      ));
    }

    if (state is AppNavigationLoggedIn) {
      pageStack.add(SlideTransitionPage<void>(
        key: AppRoutes.home.valueKey,
        name: AppRoutes.home.name,
        child: const HomeScreen(),
      ));
    }
    return pageStack;
  }

And my implementation that extends Page (not sure if that has any impact, since default MaterialPage also doesn't do transitions):

class SlideTransitionPage<T> extends Page<T> {
  final Widget child;
  final Duration duration;

  const SlideTransitionPage({
    required LocalKey? key,
    required String name,
    required this.child,
    this.duration = const Duration(milliseconds: 350),
  }) : super(key: key, name: name);

  @override
  Route<T> createRoute(BuildContext context) =>
      PageBasedSlideTransitionRoute<T>(this);
}

class PageBasedSlideTransitionRoute<T> extends PageRoute<T> {
  final SlideTransitionPage<T> page;

  PageBasedSlideTransitionRoute(this.page) : super(settings: page);

  @override
  Color? get barrierColor => null;

  @override
  String? get barrierLabel => null;

  @override
  Duration get transitionDuration => page.duration;

  @override
  bool get maintainState => true;

  @override
  Widget buildPage(
    BuildContext context,
    Animation<double> animation,
    Animation<double> secondaryAnimation,
  ) =>
      SlideTransition(
        position: animation.drive(Tween(
          begin: const Offset(1.0, 0.0),
          end: Offset.zero,
        ).chain(CurveTween(
          curve: Curves.ease,
        ))),
        child: (settings as SlideTransitionPage).child,
      );

  @override
  Widget buildTransitions(
    BuildContext context,
    Animation<double> animation,
    Animation<double> secondaryAnimation,
    Widget child,
  ) =>
      child;
}

Any suggestions what can be the reason behind it? All routers (f.e. one nested in HomeScreen and AuthScreen) perform transitions correctly. My guess is, the construction somehow causes the main router to recreate, instead of updating it's state and performing transitions, but I fail to find any solution or possible causes

ikurek
  • 604
  • 11
  • 27

1 Answers1

1

CustomRouterDelegate class edit

final List<CustomPageRouteBuilder> _pages = [];

CustomPageRouteBuilder _createPage(
      Widget child, PageConfiguration pageConfig) {
    return CustomPageRouteBuilder(
      key: Key(pageConfig.key) as LocalKey,
      pageRouteSettings: pageConfig.pageRouteSettings,
      child: child,
    );
  }

CustomPageRouteBuilder class create

class CustomPageRouteBuilder extends Page {const CustomPageRouteBuilder({
        required this.pageRouteSettings,
        required this.child,
        required LocalKey key,}) : super(key: key);
    final Widget child;
    finalPageRouteSettings pageRouteSettings;
      //Widget Function(BuildContext, Animation<double>, Animation<double>) transition;
      @override
      Route createRoute(BuildContext context) {
        return PageRouteBuilder(
          barrierColor: pageRouteSettings.barrierColor,
          opaque: pageRouteSettings.backgroundOpaque,
          barrierDismissible: pageRouteSettings.barrierDismissible,
          fullscreenDialog: pageRouteSettings.fullscreenDialog,
          settings: this,
          pageBuilder: (BuildContext context, Animation<double> animation,
              Animation<double> secondaryAnimation) {
            return FadeTransition(
              opacity: animation,
              child: child,
            );
          },
        );
      }
    }
Sefax
  • 11
  • 1