Nayef
Nayef

Reputation: 13

How to set splash screen time out on flutter

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

Answers (5)

MAlhamry
MAlhamry

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

olexa.le
olexa.le

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

Md. Yeasin Sheikh
Md. Yeasin Sheikh

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

Ravi Limbani
Ravi Limbani

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

Ashutosh singh
Ashutosh singh

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

Related Questions