'Flutter Onboarding Screen only one time
i am new to flutter and dart and i am trying to make an app with an onboarding screen with 3 pages and i am trying to skip the onboarding screen when the user has already opened the app once. I have seen something similar with the shared preferences, but i couldn't make it work.
This is my onboarding screen:
class OnboardingScreen extends StatefulWidget {
@override
_OnboardingScreenState createState() => _OnboardingScreenState();
}
class _OnboardingScreenState extends State<OnboardingScreen> {
final int _numPages = 3;
final PageController _pageController = PageController(initialPage: 0);
int _currentPage = 0;
List<Widget> _buildPageIndicator() {
List<Widget> list = [];
for (int i = 0; i < _numPages; i++) {
list.add(i == _currentPage ? _indicator(true) : _indicator(false));
}
return list;
}
Widget _indicator(bool isActive) {
return AnimatedContainer(
duration: Duration(milliseconds: 150),
margin: EdgeInsets.symmetric(horizontal: 8.0),
height: 8.0,
width: isActive ? 24.0 : 16.0,
decoration: BoxDecoration(
color: isActive ? Colors.white : Color(0xFF7B51D3),
borderRadius: BorderRadius.all(Radius.circular(12)),
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: AnnotatedRegion<SystemUiOverlayStyle>(
value: SystemUiOverlayStyle.light,
child: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
stops: [0.1, 0.4, 0.7, 0.9],
colors: [
Color(0xFF3594DD),
Color(0xFF4563DB),
Color(0xFF5036D5),
Color(0xFF5B16D0),
],
),
),
child: Padding(
padding: EdgeInsets.symmetric(vertical: 40.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Container(
alignment: Alignment.centerRight,
child: FlatButton(
onPressed: () => print('Skip'),
child: Text(
'Skip',
style: TextStyle(
color: Colors.white,
fontSize: 20.0,
),
),
),
),
Container(
height: 600.0,
child: PageView(
physics: ClampingScrollPhysics(),
controller: _pageController,
onPageChanged: (int page) {
setState(() {
_currentPage = page;
});
},
children: <Widget>[
Padding(
padding: EdgeInsets.all(40.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Center(
child: Image(
image: AssetImage(
'assets/images/lorem_Ipsum.png',
),
height: 300.0,
width: 300.0,
),
),
SizedBox(height: 30.0),
Text(
'Welcome to ...',
style: kTitleStyle,
),
SizedBox(height: 15.0),
Text(
'lorem Ipsum',
style: kSubtitleStyle,
),
],
),
),
Padding(
padding: EdgeInsets.all(40.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Center(
child: Image(
image: AssetImage(
'assets/images/lorem_Ipsum.png',
),
height: 300.0,
width: 300.0,
),
),
SizedBox(height: 30.0),
Text(
'lorem Ipsum',
style: kTitleStyle,
),
SizedBox(height: 15.0),
Text(
'lorem Ipsum',
style: kSubtitleStyle,
),
],
),
),
Padding(
padding: EdgeInsets.all(40.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Center(
child: Image(
image: AssetImage(
'assets/images/lorem_Ipsum.png',
),
height: 300.0,
width: 300.0,
),
),
SizedBox(height: 30.0),
Text(
'lorem Ipsum',
style: kTitleStyle,
),
SizedBox(height: 15.0),
Text(
'lorem Ipsum',
style: kSubtitleStyle,
),
],
),
),
],
),
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: _buildPageIndicator(),
),
_currentPage != _numPages - 1
? Expanded(
child: Align(
alignment: FractionalOffset.bottomRight,
child: FlatButton(
onPressed: () {
_pageController.nextPage(
duration: Duration(milliseconds: 500),
curve: Curves.ease,
);
},
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text(
'Next',
style: TextStyle(
color: Colors.white,
fontSize: 22.0,
),
),
SizedBox(width: 10.0),
Icon(
Icons.arrow_forward,
color: Colors.white,
size: 30.0,
),
],
),
),
),
)
: Text(''),
],
),
),
),
),
bottomSheet: _currentPage == _numPages - 1
? Container(
height: 50.0,
width: double.infinity,
color: Colors.white,
child: GestureDetector(
onTap: () => print('Get Started'),
child: Center(
child: Padding(
padding: EdgeInsets.only(bottom: 5.0),
child: Text(
'Get Started',
style: TextStyle(
color: Color(0xFF5B16D0),
fontSize: 20.0,
fontWeight: FontWeight.bold,
),
),
),
),
),
)
: Text(''),
);
}
}
Solution 1:[1]
You can use SharedPreferences
in main()
And set a initScreen
variable when first time init, set to 1 to indicate it has initialized
And In MyApp initialRoute
check initScreen
is null
to decide which route to go
You can copy paste run full code below
code snippet
int initScreen;
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
SharedPreferences prefs = await SharedPreferences.getInstance();
initScreen = await prefs.getInt("initScreen");
await prefs.setInt("initScreen", 1);
print('initScreen ${initScreen}');
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
initialRoute: initScreen == 0 || initScreen == null ? "first" : "/",
routes: {
'/': (context) => MyHomePage(
title: "demo",
),
"first": (context) => OnboardingScreen(),
},
);
}
}
full code
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:flutter/services.dart';
int initScreen;
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
SharedPreferences prefs = await SharedPreferences.getInstance();
initScreen = await prefs.getInt("initScreen");
await prefs.setInt("initScreen", 1);
print('initScreen ${initScreen}');
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
initialRoute: initScreen == 0 || initScreen == null ? "first" : "/",
routes: {
'/': (context) => MyHomePage(
title: "demo",
),
"first": (context) => OnboardingScreen(),
},
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.display1,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
class OnboardingScreen extends StatefulWidget {
@override
_OnboardingScreenState createState() => _OnboardingScreenState();
}
class _OnboardingScreenState extends State<OnboardingScreen> {
final int _numPages = 3;
final PageController _pageController = PageController(initialPage: 0);
int _currentPage = 0;
List<Widget> _buildPageIndicator() {
List<Widget> list = [];
for (int i = 0; i < _numPages; i++) {
list.add(i == _currentPage ? _indicator(true) : _indicator(false));
}
return list;
}
Widget _indicator(bool isActive) {
return AnimatedContainer(
duration: Duration(milliseconds: 150),
margin: EdgeInsets.symmetric(horizontal: 8.0),
height: 8.0,
width: isActive ? 24.0 : 16.0,
decoration: BoxDecoration(
color: isActive ? Colors.white : Color(0xFF7B51D3),
borderRadius: BorderRadius.all(Radius.circular(12)),
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: AnnotatedRegion<SystemUiOverlayStyle>(
value: SystemUiOverlayStyle.light,
child: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
stops: [0.1, 0.4, 0.7, 0.9],
colors: [
Color(0xFF3594DD),
Color(0xFF4563DB),
Color(0xFF5036D5),
Color(0xFF5B16D0),
],
),
),
child: Padding(
padding: EdgeInsets.symmetric(vertical: 40.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Container(
alignment: Alignment.centerRight,
child: FlatButton(
onPressed: () => print('Skip'),
child: Text(
'Skip',
style: TextStyle(
color: Colors.white,
fontSize: 20.0,
),
),
),
),
Container(
height: 600.0,
child: PageView(
physics: ClampingScrollPhysics(),
controller: _pageController,
onPageChanged: (int page) {
setState(() {
_currentPage = page;
});
},
children: <Widget>[
Padding(
padding: EdgeInsets.all(40.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Center(
child: Image(
image: AssetImage(
'assets/images/lorem_Ipsum.png',
),
height: 300.0,
width: 300.0,
),
),
SizedBox(height: 30.0),
Text(
'Welcome to ...',
//style: kTitleStyle,
),
SizedBox(height: 15.0),
Text(
'lorem Ipsum',
//style: kSubtitleStyle,
),
],
),
),
Padding(
padding: EdgeInsets.all(40.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Center(
child: Image(
image: AssetImage(
'assets/images/lorem_Ipsum.png',
),
height: 300.0,
width: 300.0,
),
),
SizedBox(height: 30.0),
Text(
'lorem Ipsum',
//style: kTitleStyle,
),
SizedBox(height: 15.0),
Text(
'lorem Ipsum',
//style: kSubtitleStyle,
),
],
),
),
Padding(
padding: EdgeInsets.all(40.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Center(
child: Image(
image: AssetImage(
'assets/images/lorem_Ipsum.png',
),
height: 300.0,
width: 300.0,
),
),
SizedBox(height: 30.0),
Text(
'lorem Ipsum',
//style: kTitleStyle,
),
SizedBox(height: 15.0),
Text(
'lorem Ipsum',
//style: kSubtitleStyle,
),
],
),
),
],
),
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: _buildPageIndicator(),
),
_currentPage != _numPages - 1
? Expanded(
child: Align(
alignment: FractionalOffset.bottomRight,
child: FlatButton(
onPressed: () {
_pageController.nextPage(
duration: Duration(milliseconds: 500),
curve: Curves.ease,
);
},
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text(
'Next',
style: TextStyle(
color: Colors.white,
fontSize: 22.0,
),
),
SizedBox(width: 10.0),
Icon(
Icons.arrow_forward,
color: Colors.white,
size: 30.0,
),
],
),
),
),
)
: Text(''),
],
),
),
),
),
bottomSheet: _currentPage == _numPages - 1
? Container(
height: 50.0,
width: double.infinity,
color: Colors.white,
child: GestureDetector(
onTap: () => print('Get Started'),
child: Center(
child: Padding(
padding: EdgeInsets.only(bottom: 5.0),
child: Text(
'Get Started',
style: TextStyle(
color: Color(0xFF5B16D0),
fontSize: 20.0,
fontWeight: FontWeight.bold,
),
),
),
),
),
)
: Text(''),
);
}
}
Solution 2:[2]
Most times you will need to go from onboarding to login to mainscreen
class OnboardingScreen extends StatefulWidget {
OnboardingScreen({
Key ? key
}): super(key: key);
@override
State < OnboardingScreen > createState() => _onboardingScreenState();
}
class _onboardingScreenState extends State < OnboardingScreen > {
@override
Widget build(BuildContext context) {
return Container(
child: Center(
child: GestureDetector(
onTap: () {
IsFirstTime().once(1);
//navigate
},
child: Text('Login screen something')),
));
}
}
onbo
class login extends StatefulWidget {
login({
Key ? key
}): super(key: key);
@override
State < login > createState() => _loginState();
}
class _loginState extends State < login > {
@override
Widget build(BuildContext context) {
return Container(
child: Center(
child: GestureDetector(
onTap: () {
IsFirstTime().once(2);
//navigate to mainscreen
},
child: Text('Login screen something')),
));
}
}
Future < void > main() async {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({
Key ? key
}): super(key: key);
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle(
statusBarColor: Colors.transparent, // transparent status bar
statusBarIconBrightness: Brightness.dark // dark text for status bar
));
//get stored int from sharedpref
Future < int > alreadyAUser = IsFirstTime().getOnce();
return MultiProvider(
providers: AppProviders.providers,
child: MaterialApp(
debugShowCheckedModeBanner: false,
routes: AppRoutes.routes(),
home: FutureBuilder(
builder: (ctx, snapshot) {
// Checking if future is resolved or not
if (snapshot.connectionState == ConnectionState.done) {
// If data is present
if (snapshot.hasData) {
final data = snapshot.data as int;
print(data);
switch (data) {
case 0:
return OnboardingScreen();
case 1:
return LoginScreen();
case 2:
return MainScreen();
}
// if we got our data
}
}
// Displaying blank to indicate waiting state
return Container(
color: Colors.white,
);
},
// Future that needs to be resolved
// inorder to display something on the Canvas
future: alreadyAUser,
),
),
);
}
}
-->
class IsFirstTime {
Future < int > getOnce() async {
int ? intValue;
SharedPreferences prefs = await SharedPreferences.getInstance();
//Return String
if (prefs.getInt("initScreen") == null) {
intValue = 0;
} else {
intValue = prefs.getInt("initScreen");
}
return intValue!;
}
Future once(int num) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
//initScreen
await prefs.setInt("initScreen", num);
int initScreen = (prefs.getInt("initScreen")) !;
print('initScreen ${initScreen}');
// return initScreen;
}
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | Ayoseun Francis Solomon |