18

How to show splash screen in flutter for 3 seconds and then go next my login screen.

I have tried.countdowntimer but import is unresolved

import 'package: countDown/countDown.dart';
CountDown cd  =  new CountDown(new Duration(seconds: 4));
CountDown is unresolved 

Android Studio & Flutter

Quick learner
  • 10,632
  • 4
  • 45
  • 55
Deepak Ror
  • 2,084
  • 2
  • 20
  • 26

11 Answers11

34

Simple solution which i use in every app.

Use Timer class in build method code snippet

class SplashScreen extends StatefulWidget {
  @override
  Splash createState() => Splash();
}

class Splash extends State<SplashScreen>  {

  @override
  void initState() {
    super.initState();

  }
  @override
  Widget build(BuildContext context) {
        Timer(
            Duration(seconds: 3),
                () =>
            Navigator.of(context).pushReplacement(MaterialPageRoute(
                builder: (BuildContext context) => LandingScreen())));


    var assetsImage = new AssetImage(
        'images/new_logo.png'); //<- Creates an object that fetches an image.
    var image = new Image(
        image: assetsImage,
        height:300); //<- Creates a widget that displays an image.

    return MaterialApp(
      home: Scaffold(
        /* appBar: AppBar(
          title: Text("MyApp"),
          backgroundColor:
              Colors.blue, //<- background color to combine with the picture :-)
        ),*/
        body: Container(
          decoration: new BoxDecoration(color: Colors.white),
          child: new Center(
            child: image,
          ),
        ), //<- place where the image appears
      ),
    );
  }
}
Quick learner
  • 10,632
  • 4
  • 45
  • 55
  • If I press back button. Wouldn't I come back to the splash screen? – GunJack Jun 04 '20 at 06:13
  • What is the current situation when you press back button ? Can you tell me so I can update answer – Quick learner Jun 04 '20 at 06:20
  • Its okay now. I wasn't aware about the `pushReplacement()` method. But I did a weird thing. In main.dart, I defined `LandingScreen()` and then in its `initState()`, I did `pushReplacement` to `SplashScreen()`. SplashScreen have this code You provided here. I was trying to achieve this without changing the home: in `main.dart`. It ended up in all kinds of error. – GunJack Jun 04 '20 at 07:50
  • Okay I got you.. I provided the first screen after main ..if you want me to provide main.dart class also I can update code as well – Quick learner Jun 04 '20 at 08:08
  • I understand what you did and I made it working now. – GunJack Jun 04 '20 at 08:13
  • I know this is off topic, but while the splash screen is being displayed. Can I fetch json data in background? – GunJack Jun 04 '20 at 09:09
  • 1
    You need to use a background plugin to do task in background ,but background plugin might not work in IOS ,you if I had to get data in background I would have just looked for any other way – Quick learner Jun 04 '20 at 09:21
19

refer bellow main.dart

import 'dart:async';    
import 'package:flutter/material.dart';    
import 'src/login_screen.dart';

void main() {
  runApp(new MaterialApp(
    home: new MyApp(),
  ));
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => new _MyAppState();
}

class _MyAppState extends State<MyApp> {
  @override
  void initState() {
    super.initState();
    new Future.delayed(
        const Duration(seconds: 3),
        () => Navigator.push(
              context,
              MaterialPageRoute(builder: (context) => LoginScreen()),
            ));
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      backgroundColor: Colors.white,
      body: Container(
        child: new Column(children: <Widget>[
          Divider(
            height: 240.0,
            color: Colors.white,
          ),
          new Image.asset(
            'assets/logo.png',
            fit: BoxFit.cover,
            repeat: ImageRepeat.noRepeat,
            width: 170.0,
          ),
          Divider(
            height: 105.2,
            color: Colors.white,
          ),
        ]),
      ),
    );
  }
}

Hope this will helps you

Rahul Mahadik
  • 11,668
  • 6
  • 41
  • 54
13

You can execute code with a delay using Future.delayed

new Future.delayed(const Duration(seconds: 3), () {
  Navigator.pushNamed(context, '/login');
});

update

const delay = 3;
widget.countdown = delay;

StreamSubscription sub;
sub = new Stream.periodic(const Duration(seconds: 1), (count) {
  setState(() => widget.countdown--);  
  if(widget.countdown <= 0) {
    sub.cancel();
    Navigator.pushNamed(context, '/login');
  }
});     
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
4

Future.delayed would be a good solution without a countdown.

But considering you have a countdown, you can use the animation framework Flutter provides.

The idea behind it would be to use an AnimationController with a duration of 3 seconds. Start the animation as soon as the splashScreen is instantiated. And add a listener to redirect to /login on animation end.

Then pass that controller to an AnimationBuilder which would handle the formating of your countdown based on animationController.lastElaspedDuration.

class SplashScreen extends StatefulWidget {
  final Duration duration;

  const SplashScreen({this.duration});

  @override
  _SplashScreenState createState() => new _SplashScreenState();
}

class _SplashScreenState extends State<SplashScreen> with SingleTickerProviderStateMixin {
  AnimationController animationController;

  @override
  void initState() {
    animationController = new AnimationController(duration: widget.duration, vsync: this)
      ..forward()
      ..addStatusListener((status) {
        if (status == AnimationStatus.completed) {
          Navigator.pushReplacementNamed(context, '/login');
        }
      });
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return new AnimatedBuilder(
      animation: animationController,
      builder: (context, _) {
        return new Center(
          child: new Text(animationController.lastElapsedDuration.inSeconds.toString()),
        );
      },
    );
  }
}
Rémi Rousselet
  • 256,336
  • 79
  • 519
  • 432
3

I needed a widget with 5 seconds delay. My solution was as following:

class Waiting extends StatefulWidget {
  @override
  _WaitingState createState() => _WaitingState();
}

class _WaitingState extends State<Waiting> {
  bool voxt = false;

  @override
  Widget build(BuildContext context) {
    return FutureBuilder(
      future: Future.delayed(Duration(seconds: 3)),
      builder: (c, s) => s.connectionState != ConnectionState.done
          ? Text('Waiting')
          : Text('3 sec passed')
    );
  }
}

Now Waiting widget can be called where needed.

1

The cleanest approach without adding explicit timers.

Use Time based SplashScreen.

class TimeBasedSplash extends State<MyApp>{

  @override
  Widget build(BuildContext context) {
    return new SplashScreen(
      seconds: 10,
      navigateAfterSeconds: new HomeScreen(),// Where to navigate after 10 secs
      image: new Image.asset('assets/images/flutter_logo.png'),
      photoSize: 200,
      loaderColor: Colors.white,
      styleTextUnderTheLoader : const TextStyle(fontSize: 18.0, fontWeight: FontWeight.bold, color: Colors.white),
     loadingText: new Text('Loading...'),
      gradientBackground: LinearGradient(
        begin: Alignment.topCenter,
        end: Alignment.bottomCenter,
        colors: <Color>[
          Colors.lightBlue,
          Colors.indigo
        ],
      ),
    );
  }

}

In main class

void main(){
  runApp(new MaterialApp(
    home: new MyApp(),
  ));
}


class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => new _MyAppState();
}

class _MyAppState extends State<MyApp> {
  @override
  Widget build(BuildContext context) {
    return new TimeBasedSplash().build(context);
  }
}
1

You can also create a splashScreen within a StatlessWidget(). Inside the MaterialApp() under home:

home: FutureBuilder(
        future: Future.delayed(Duration(seconds: 3)),
        builder: (ctx, timer) => timer.connectionState == ConnectionState.done
            ? ProfileScreen() //Screen to navigate to once the splashScreen is done.
            : Container(
                color: Colors.white,
                child: Image(
                  image: AssetImage('assets/images/download.png'),
                ),
              )),
Ole Pannier
  • 3,208
  • 9
  • 22
  • 33
DARTender
  • 424
  • 2
  • 7
0

I think you need to clear the old activity from stack (Splash Screen), So you have to use pushNamedAndRemoveUntil instead of using pushNamed only.

  new Future.delayed(const Duration(seconds: 3), () {
  Navigator.pushNamedAndRemoveUntil(context, '/login', ModalRoute.withName('/'));
});
0

This answer is applicable only in case you are using flutter-redux.

Along with flutter-redux you need to use redux-persist library to show loading screen.

redux-persist is used to store, rehydrate app state.

Example:

1.main.dart

import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter_redux/flutter_redux.dart';
import 'package:redux_persist_flutter/redux_persist_flutter.dart';

import 'package:flutter_redux_starter/presentation/platform_adaptive.dart';
import 'package:flutter_redux_starter/screens/loading_screen.dart';
import 'package:flutter_redux_starter/store/store.dart';
import 'package:flutter_redux_starter/middleware/middleware.dart';
import 'package:flutter_redux_starter/models/app_state.dart';
import 'package:flutter_redux_starter/routes.dart';


void main() => runApp(new MyApp());

class MyApp extends StatelessWidget {
    final store = createStore();

    MyApp();

    @override
    Widget build(BuildContext context) {
        return new PersistorGate(
            persistor: persistor,
            loading: new LoadingScreen(),
            builder: (context) => new StoreProvider<AppState>(
                store: store,
                child: new MaterialApp(
                    title: 'Flutter test App',
                    theme: defaultTargetPlatform == TargetPlatform.iOS
                        ? kIOSTheme
                        : kDefaultTheme,
                routes: getRoutes(context, store),
                    initialRoute: '/login',
                )
            ),
        );
    }

}

2.store.dart

import 'package:redux/redux.dart';

import 'package:flutter_redux_starter/reducers/app_reducer.dart';
import 'package:flutter_redux_starter/models/app_state.dart';
import 'package:flutter_redux_starter/middleware/middleware.dart';

Store<AppState> createStore() { 
    Store<AppState> store = new Store(
        appReducer,
        initialState: new AppState(),
        middleware: createMiddleware(),
    );
    persistor.start(store);

    return store;
}

In createStore you can use Future.delayed to delay the creation of store for certain no of seconds.

new Future.delayed(const Duration(seconds: 3), () {
 // 
});
WitVault
  • 23,445
  • 19
  • 103
  • 133
0

You can use Future.delayed constructor in your initState. This will keep your SplashScreen for the duration you specify before the navigation happen.

class SplashScreen extends StatefulWidget {
  @override
  _SplashScreenState createState() => new _SplashScreenState();
}

class _SplashScreenState extends State<SplashScreen> {
  @override
  void initState (){
    super.initState();
    // TODO initial state stuff
    new Future.delayed(const Duration(seconds: 4));
  }
  @override
  Widget build(BuildContext context) {
    //build
  }
}

I only copied the answers from:this

R Rifa Fauzi Komara
  • 1,915
  • 6
  • 27
  • 54
0

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 O'neya answer 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(),
          ],
        ),
      ),
    ),
  );
}
MAlhamry
  • 323
  • 1
  • 8