27

so I was following bloc login tutorial, and while I managed to complete it, I'm still fairly new to Flutter & Dart.

There is a portion of the code where, depending on the state, the code returns a different widget, instead of a new Scaffold. Since it's not using routes, the transition between pages looks choppy and akward.

return BlocProvider<AuthenticationBloc>(
  bloc: authenticationBloc,
  child: MaterialApp(
    debugShowCheckedModeBanner: false,
    home: BlocBuilder<AuthenticationEvent, AuthenticationState>(
      bloc: authenticationBloc,
      builder: (BuildContext context, AuthenticationState state) {
        if (state is AuthenticationUninitialized) {
          return SplashPage();
        }
        if (state is AuthenticationAuthenticated) {
          return HomePage();
        }
        if (state is AuthenticationUnauthenticated) {
          return LoginPage(userRepository: userRepository);
        }
        if (state is AuthenticationLoading) {
          return LoadingIndicator();
        }
      },
    ),
  ),
);

I've tried adding a Navigation.push wrapping the returns, like this:

if (state is AuthenticationUninitialized) {
  Navigation.push(
    return SplashPage();
  ),
}

But while is not syntactically wrong, that crashes the app. Does anyone know a way to implement this while maintaining the BLoC example? Thanks.

David
  • 5,882
  • 3
  • 33
  • 44
herrmartell
  • 3,057
  • 4
  • 18
  • 27

1 Answers1

32

You can wrap the pages with AnimatedSwitcher:

return BlocProvider<AuthenticationBloc>(
  bloc: authenticationBloc,
  child: MaterialApp(
    home: BlocBuilder<AuthenticationEvent, AuthenticationState>(
      bloc: authenticationBloc,
      builder: (BuildContext context, AuthState state) {
        return AnimatedSwitcher(
          duration: Duration(milliseconds: 250),
          child: _buildPage(context, state),
        );
      },
    ),
  ),
);

By default it uses fade transition and animates old and new widgets in reverse order.


To keep old widget in place during animation, pass to AnimatedSwitcher

switchOutCurve: Threshold(0),

To mimic Navigator.push transition in Android, pass it

transitionBuilder: (Widget child, Animation<double> animation) {
  return SlideTransition(
    position: Tween<Offset>(
      begin: const Offset(0, 0.25),
      end: Offset.zero,
    ).animate(animation),
    child: child,
  );
},

To use system transitions, try something like

transitionBuilder: (Widget child, Animation<double> animation) {
  final theme = Theme.of(context).pageTransitionsTheme;
  final prev = MaterialPageRoute(builder: (_) => widget);
  return theme.buildTransitions(prev, context, animation, null, child);
},

(the last isn't tested well)

FGoo
  • 93
  • 1
  • 5
Pavel
  • 5,374
  • 4
  • 30
  • 55
  • 3
    Also, the child of AnimatedSwitcher must have a Key to denote the change. If you don't want to modify your child Widget (either it is StatelessWidget or StatefulWidget with own key) wrap it with Container and set Container key to: UniqueKey(). – Michał Dobi Dobrzański Oct 15 '19 at 11:49