Reputation: 13
I am new to flutter and am kinda lost on how to set up a time to my splash screen so after this time it goes to the main screen. am using rive for the splash screen
import 'package:flutter/material.dart';
import 'package:rive/rive.dart';
void main() {
runApp(const MaterialApp(home: SimpleAnimation()));
}
class SimpleAnimation extends StatelessWidget {
const SimpleAnimation({Key? key, this.loading}) : super(key: key);
final bool? loading;
@override
Widget build(BuildContext context) {
return const Scaffold(
body: Center(
child: RiveAnimation.asset('assets/splash/splash.riv',
fit: BoxFit.cover)
),
);
}
}
Upvotes: 0
Views: 3098
Reputation: 373
This is my approach for splash screen, the advantage of this approach is to make sure that the splash screen launch only once when the app starting.
First define a static bool in app home class to indicate the app launch.
static bool launch = true;
Then at the home attribute in your MaterialApp widget at app home class, check if (launch) is true use a FutureBuilder to launch the splash screen, if (launch) is false set home to your second screen. With FutureBuilder you can set a timer for your splash screen, when it done your second screen will start (credit to https://stackoverflow.com/a/68699447/11619215).
home: launch? FutureBuilder(
future: Future.delayed(const Duration(seconds: 3)),
builder: (ctx, timer) =>
timer.connectionState == ConnectionState.done
? const SecondScreen(title: 'Flutter Demo Home Page')
: appSplashScreen(),
): const SecondScreen(title: 'Flutter Demo Home Page'),
In the Second screen, check if (launch) is true then set it to false. This will make sure that the splash screen will only launch once each time your application start.
if(AppHome.launch) {
AppHome.launch = false;
}
Below is the full code with appSplashScreen widget at the bottom:
import 'package:flutter/material.dart';
void main() {
runApp(const AppHome());
}
class AppHome extends StatelessWidget {
const AppHome({Key? key}) : super(key: key);
//static bool to indicate the launching of the app
static bool launch = true;
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: launch? FutureBuilder(
future: Future.delayed(const Duration(seconds: 3)),
builder: (ctx, timer) =>
timer.connectionState == ConnectionState.done
? const SecondScreen(title: 'Flutter Demo Home Page')
: appSplashScreen(),
): const SecondScreen(title: 'Flutter Demo Home Page'),
);
}
}
class SecondScreen extends StatefulWidget {
const SecondScreen({Key? key, required this.title}) : super(key: key);
final String title;
@override
State<SecondScreen> createState() => _SecondScreenState();
}
class _SecondScreenState extends State<SecondScreen> {
@override
Widget build(BuildContext context) {
//mack sure your splash screen only launch once at your app starting
if(AppHome.launch) {
AppHome.launch = false;
}
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: const Center(
child: Text(
'My Second screen',
),
),
);
}
}
Widget appSplashScreen() {
return Container(
decoration: const BoxDecoration(
////you can add background image/color to your splash screen
// image: DecorationImage(
// image: AssetImage('assets/background.png'),
// fit: BoxFit.cover,
// ),
color: Colors.white,
),
child: Center(
child: SizedBox(
//get MediaQuery from instance of window to get height and width (no need of context)
height: MediaQueryData.fromWindow(WidgetsBinding.instance.window).size.height*0.5,
width: MediaQueryData.fromWindow(WidgetsBinding.instance.window).size.width*0.5,
child: Column(
children: const [
////you can add image to your splash screen
// Image(
// image: AssetImage('assets/splashscreen_image.png'),
// ),
FittedBox(
child: Text(
'Loading',
textAlign: TextAlign.center,
style: TextStyle(
decoration: TextDecoration.none,
),
)
),
CircularProgressIndicator(),
],
),
),
),
);
}
Upvotes: 0
Reputation: 1807
As folks already mentioned the straighforward way would be to add a delay and do navigation after it:
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return const MaterialApp(
title: 'Flutter Demo',
home: SplashScreen(),
);
}
}
class SplashScreen extends StatefulWidget {
const SplashScreen({Key? key}) : super(key: key);
@override
State<SplashScreen> createState() => _SplashScreenState();
}
class _SplashScreenState extends State<SplashScreen> {
@override
void initState() {
super.initState();
Future.delayed(const Duration(seconds: 2), () {
if (mounted) {
Navigator.of(context).pushReplacement(
MaterialPageRoute(
builder: (context) => const MainScreen(),
),
);
}
});
}
@override
Widget build(BuildContext context) {
return const ColoredBox(color: Colors.green);
}
}
class MainScreen extends StatelessWidget {
const MainScreen({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return const ColoredBox(color: Colors.yellow);
}
}
Though, with this implementation, you'll have to depend on the animation length. So when you'll update animation - you'll have not to forget to update it inside the splash screen. A more reliable (and complex) solution would be to listen to the animation status and do the navigation after the animation finishes. Like this (warning, change ):
class PlayOneShotAnimation extends StatefulWidget {
const PlayOneShotAnimation({Key? key}) : super(key: key);
@override
_PlayOneShotAnimationState createState() => _PlayOneShotAnimationState();
}
class _PlayOneShotAnimationState extends State<PlayOneShotAnimation> {
late RiveAnimationController _controller;
@override
void initState() {
super.initState();
_controller = OneShotAnimation(
'bounce',
autoplay: true,
onStop: () {
Navigator.of(context).push(
MaterialPageRoute<void>(
builder: (context) => const MainScreen(),
),
);
},
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: RiveAnimation.network(
'https://cdn.rive.app/animations/vehicles.riv',
animations: const ['idle', 'curves'],
controllers: [_controller],
),
),
);
}
}
class MainScreen extends StatelessWidget {
const MainScreen({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return const ColoredBox(color: Colors.yellow);
}
}
Upvotes: 1
Reputation: 63669
This SimpleAnimation
widget shows after the splash screen. While this is StatelessWidget
widget, you can define method inside build
method. Change Duration(seconds: 2)
based on your need.
class SimpleAnimation extends StatelessWidget {
const SimpleAnimation({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
Future.delayed(const Duration(seconds: 2)).then((value) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const NextScreen(),
));
});
return const Scaffold(
body: Center(
Upvotes: 2
Reputation: 1172
You can set 3 second time in initstate after navigate to which screen you want
class SplashScreen extends StatefulWidget {
const SplashScreen({Key? key}) : super(key: key);
@override
_SplashScreenState createState() => _SplashScreenState();
}
class _SplashScreenState extends State<SplashScreen> {
@override
void initState() {
// TODO: implement initState
super.initState();
// after 3 second it will navigate
Future.delayed(const Duration(seconds: 3)).then((val) {
// Navigation Here
});
}
@override
Widget build(BuildContext context) {
return const Scaffold(
// your code
);
}
}
Upvotes: 2
Reputation: 954
@override
void initState() {
//set timer for splash screen
Timer(const Duration(seconds: 4), () async {
//add your logic here
Navigator.pushNamedAndRemoveUntil(
context, ScreenRoute.mainScreen, (route) => false);
super.initState();
}
Upvotes: 2