How would you approach adding a splash screen to Flutter apps? It should load and display before any other content. Currently there is a brief flash of color before the Scaffold(home:X) widget loads.
问题:
回答1:
I want to bring some more light to the actual way of doing Splash screen in Flutter.
I followed a little bit the trace here and I saw that things aren't looking so bad about the Splash Screen in Flutter.
Maybe most of the devs (like me) are thinking that there is not Splash screen by default in Flutter and they need to do something about that. Actually there is Splash screen, but it is with white background and nobody can understand that there is already splash screen for iOS and Android by default.
This is actually cool, because the only thing that the developer needs to do is to put the Branding image on the right place and the splash screen will start working just like that.
Now here is how this can be done, step by step:
First for Android (because is my favorite Platform :) )
Find the "android" folder in your Flutter project.
Browse to app -> src -> main -> res folder and place all of the variants of your branding image in the corresponding folders. For example:
- the image with density 1 needs to be placed in mipmap-mdpi,
- the image with density 1.5 needs to be placed in mipmap-hdpi,
- the image with density 2 needs to be placed in mipmap-xdpi,
- the image with density 3 needs to be placed in mipmap-xxdpi,
- the image with density 4 needs to be placed in mipmap-xxxdpi,
By default for the android folder there isn't drawable-mdpi, drawable-hdpi etc., but everybody can create if he wants. That's why the images need to be placed in mipmap folders. Plus that the default XML code about the Splash screen (in Android) is going to have a look in @mipmap not in @drawable (you can change it if you want).
The last step in Android is to uncomment some code in drawable/launch_background.xml. Browse to app -> src -> main -> res-> drawable and open launch_background.xml. Inside this file you will see why the Slash screen background is white. To apply the branding image that we placed in step 2, we have to uncommented some of the XML code in your launch_background.xml file, so after the change the code should look like:
<!--<item android:drawable="@android:color/white" />--> <item> <bitmap android:gravity="center" android:src="@mipmap/your_image_name" /> </item>
Please pay attention that we comment the white background code and uncomment the code about the mipmap image. If somebody is interested, this launch_background.xml is used in styles.xml file.
Now for iOS:
Find the "ios" folder in your Flutter project.
Browse to Runner -> Assets.xcassets -> LaunchImage.imageset. There should be LaunchImage.png, LaunchImage@2x.png etc. Now you have to replace these images with you branding image variants. For example:
- the image with density 1 needs to override LaunchImage.png,
- the image with density 2 needs to override LaunchImage@2x.png,
- the image with density 3 needs to override LaunchImage@3x.png,
- the image with density 4 needs to override LaunchImage@4x.png,
If I am not wrong LaunchImage@4x.png does not exist by default, but you can easily create one. If LaunchImage@4x.png doesn't exist, you have to declare it in the Contents.json file as well, which is in the same directory like the images. After the change my Contents.json file looks like this :
{
"images" : [
{
"idiom" : "universal",
"filename" : "LaunchImage.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "LaunchImage@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "LaunchImage@3x.png",
"scale" : "3x"
},
{
"idiom" : "universal",
"filename" : "LaunchImage@4x.png",
"scale" : "4x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
And that should be all. Next time when you run your app, on Android and iOS you should have the right Splash Screen with the branding image that you added.
Thanks
回答2:
There isn't a good example of this yet, but you can do it yourself using the native tools for each platform:
iOS: https://docs.nativescript.org/publishing/creating-launch-screens-ios
Android: https://www.bignerdranch.com/blog/splash-screens-the-right-way/
Subscribe to issue 8147 for updates on example code for splash screens. If the black flicker between the splash screen and the app on iOS bothers you, subscribe to issue 8127 for updates.
Edit: As of August 31, 2017, improved support for splash screens is now available in the new project template. See #11505.
回答3:
You should try below code, worked for me
import 'dart:async';
import 'package:attendance/components/appbar.dart';
import 'package:attendance/homepage.dart';
import 'package:flutter/material.dart';
class _SplashScreenState extends State<SplashScreen>
with SingleTickerProviderStateMixin {
void handleTimeout() {
Navigator.of(context).pushReplacement(new MaterialPageRoute(
builder: (BuildContext context) => new MyHomePage()));
}
startTimeout() async {
var duration = const Duration(seconds: 3);
return new Timer(duration, handleTimeout);
}
@override
void initState() {
// TODO: implement initState
super.initState();
_iconAnimationController = new AnimationController(
vsync: this, duration: new Duration(milliseconds: 2000));
_iconAnimation = new CurvedAnimation(
parent: _iconAnimationController, curve: Curves.easeIn);
_iconAnimation.addListener(() => this.setState(() {}));
_iconAnimationController.forward();
startTimeout();
}
@override
Widget build(BuildContext context) {
return new Scaffold(
body: new Scaffold(
body: new Center(
child: new Image(
image: new AssetImage("images/logo.png"),
width: _iconAnimation.value * 100,
height: _iconAnimation.value * 100,
)),
),
);
}
}
回答4:
If you flutter create
d your project, you can follow the steps at https://flutter.io/assets-and-images/#updating-the-launch-screen.
回答5:
Both @Collin Jackson and @Sniper are right. You can follow these steps to set up launch images in android and iOS respectively. Then in your MyApp(), in your initState(), you can use Future.delayed to set up a timer or call any api. Until the response is returned from the Future, your launch icons will be shown and then as the response come, you can move to the screen you want to go to after the splash screen. You can see this link : Flutter Splash Screen
回答6:
For Android, go to android > app > src > main > res > drawable > launcher_background.xml
Now uncomment this and replace @mipmap/launch_image, with your image location.
<item>
<bitmap
android:gravity="center"
android:src="@mipmap/launch_image" />
</item>
You can change the colour of your screen here -
<item android:drawable="@android:color/white" />
回答7:
persons who are getting the error like image not found after applying the verified answer make sure that you are adding @mipmap/ic_launcher instead of @mipmap/ ic_launcher.png
回答8:
Adding a page like below and routing might help
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutkart/utils/flutkart.dart';
import 'package:flutkart/utils/my_navigator.dart';
class SplashScreen extends StatefulWidget {
@override
_SplashScreenState createState() => _SplashScreenState();
}
class _SplashScreenState extends State<SplashScreen> {
@override
void initState() {
// TODO: implement initState
super.initState();
Timer(Duration(seconds: 5), () => MyNavigator.goToIntro(context));
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
fit: StackFit.expand,
children: <Widget>[
Container(
decoration: BoxDecoration(color: Colors.redAccent),
),
Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Expanded(
flex: 2,
child: Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
CircleAvatar(
backgroundColor: Colors.white,
radius: 50.0,
child: Icon(
Icons.shopping_cart,
color: Colors.greenAccent,
size: 50.0,
),
),
Padding(
padding: EdgeInsets.only(top: 10.0),
),
Text(
Flutkart.name,
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 24.0),
)
],
),
),
),
Expanded(
flex: 1,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
CircularProgressIndicator(),
Padding(
padding: EdgeInsets.only(top: 20.0),
),
Text(
Flutkart.store,
softWrap: true,
textAlign: TextAlign.center,
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 18.0,
color: Colors.white),
)
],
),
)
],
)
],
),
);
}
}
If you want to follow through, see: https://www.youtube.com/watch?v=FNBuo-7zg2Q
回答9:
The code from Jaldhi Bhatt doesn't works for me.
Flutter throws a 'Navigator operation requested with a context that does not include a Navigator.'
I fixed the code wrapping the Navigator consumer component inside of another component that initialize the Navigator context using routes, as mentioned in this article.
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:my-app/view/main-view.dart';
class SplashView extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
home: Builder(
builder: (context) => new _SplashContent(),
),
routes: <String, WidgetBuilder>{
'/main': (BuildContext context) => new MainView()}
);
}
}
class _SplashContent extends StatefulWidget{
@override
_SplashContentState createState() => new _SplashContentState();
}
class _SplashContentState extends State<_SplashContent>
with SingleTickerProviderStateMixin {
var _iconAnimationController;
var _iconAnimation;
startTimeout() async {
var duration = const Duration(seconds: 3);
return new Timer(duration, handleTimeout);
}
void handleTimeout() {
Navigator.pushReplacementNamed(context, "/main");
}
@override
void initState() {
super.initState();
_iconAnimationController = new AnimationController(
vsync: this, duration: new Duration(milliseconds: 2000));
_iconAnimation = new CurvedAnimation(
parent: _iconAnimationController, curve: Curves.easeIn);
_iconAnimation.addListener(() => this.setState(() {}));
_iconAnimationController.forward();
startTimeout();
}
@override
Widget build(BuildContext context) {
return new Center(
child: new Image(
image: new AssetImage("images/logo.png"),
width: _iconAnimation.value * 100,
height: _iconAnimation.value * 100,
)
);
}
}
回答10:
Multiple ways you could do this, but the easiest one which I use is:
For Launch Icons I use the flutter library Flutter Launcher Icon
For the Custom Splash Screen I create different Screen resolutions and then add the splash images in the mipmap folder as per the resolution for Android.
The last part is adjusting the launch_background.xml in the drawable folder in res folder in Android.
Just change your code to look like below:
<?xml version="1.0" encoding="utf-8"?>
<!-- Modify this file to customize your launch splash screen -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!-- <item android:drawable="@android:color/white" />
<item android:drawable="@drawable/<splashfilename>" /> --> -->
<!-- You can insert your own image assets here -->
<item>
<bitmap
android:gravity="center"
android:src="@mipmap/<Your splash image name here as per the mipmap folder>"/>
</item>
</layer-list>
Few devs I have seen add the splash as drawable, I tried this but somehow the build fails in Flutter 1.0.0 and Dart SDK 2.0+. Therefore I prefer to add the splash in bitmap section.
iOS Splash-screen creation is rather simpler.
In the Runner folder in iOS just update the LaunchImage.png files with your custom Splash screen images with same names as LaunchImage.png @2x, @3x, @4x.
Just an addition I feel its good to have a 4x image as well in the LaunchImage.imageset. Just update your code in Content.json with following lines, below 3x scale to add a 4x scale option:
{
"idiom" : "universal",
"filename" : "LaunchImage@4x.png",
"scale" : "4x"
}