I have an intro screen for my app, but it shows every time I open the app, I need to show that for the 1st time only.
How to do that?
//
I took a different approach. I agree with the other answers that you should save your isFirstRun
status via SharedPreferences
. The tricky part then is how to show the correct widget in such a way that when you hit back you close out of the app correctly, etc. I first tried doing this by launching a my SplashWidget
while building my HomePageWidget
, but this turned out to lead to some weird Navigator
errors.
Instead, I wound up calling runApp()
multiple times with my different widget as appropriate. When I need to close the SplashWidget
, rather than pop it, I just call runApp()
again, this time with my HomePageWidget
as the child
property. It is safe to call runApp()
multiple times according to this issue, indeed even for splash screens.
So it looks something like this (simplified obviously):
Future main() async {
bool needsFirstRun = await retrieveNeedsFirstRunFromPrefs();
if (needsFirstRun) {
// This is will probably be an async method but no need to
// delay the first widget.
saveFirstRunSeen();
runApp(child: SplashScreenWidget(isFirstRun: true));
} else {
runApp(child: HomePageWidget());
}
}
I have an isFirstRun
property on SplashScreenWidget
because I can launch it in two ways--once as a true splash screen, and once from settings so that users can see it again if they want. I then inspect that in SplashScreenWidget
to determine how I should return to the app.
class SplashScreenWidget extends StatefulWidget {
final bool isFirstRun;
// the constructor and getState()
}
class _SplashScreenWidgetState extends State {
// This is invoked either by a 'skip' button or by completing the
// splash screen experience. If they just hit back, they'll be
// kicked out of the app (which seems like the correct behavior
// to me), but if you wanted to prevent that you could build a
// WillPopScope widget that instead launches the home screen if
// you want to make sure they always see it.
void dismissSplashScreen(BuildContext ctx) {
if (widget.isFirstRun) {
// Then we can't just Navigator.pop, because that will leave
// the user with nothing to go back to. Instead, we will
// call runApp() again, setting the base app widget to be
// our home screen.
runApp(child: HomePageWidget());
} else {
// It was launched via a MaterialRoute elsewhere in the
// app. We want the dismissal to just return them to where
// they were before.
Navigator.of(ctx).pop();
}
}
}