Skip to main content

Fix Blank Screen issue on app start by Splash Screen

 

Flutter - Splash Screen for Android and iOS


What is Splash Screen?

Splash Screen (or Launch Screen on iOS) is the very first page of your app seen by users. So it would be great to make a good first impression. I would like to present you a few ways to create a splash screen in your Flutter application using native solutions or Flutter package. Our goal is to create splash screens as shown below (from left: iOS 15, Android 12, Android 8):





iOS

Launch Screen using Storyboard

We are able to set a splash screen for iOS in two ways. The first one is by using Storyboard.

1.    First of all, we need to open our project in Xcode. Being in the main directory of the project, we can do that using open ios/Runner.xcworkspace command.

2.    Then, we need to add AssetImage, which is going to be our icon on the splash screen. As you can see in the image below, we need to provide 3 different resolutions of an icon: 1x, 2x and 3x (more details here)

3.    Then, we need to set a background color in LaunchScreen.storyboard as in the image below.


4.    That is all. Our splash screen should appear after building the app.

TIP 1: If you can’t see changes to your splash screen, try to delete the app from the phone/simulator, restart the phone/simulator, go to Xcode→Product→Clean Build Folder. That should solve the issue.

Launch Screen using Info.plist

The second approach uses Info.plist file (Information Property List).

1.    Remove LaunchScreen.storyboard file using Xcode (it is important to use Xcode to remove all dependencies to that file).




2.    Then, add New Color Set inside Assets.xcassets. We are able to define different colors for light and dark themes.

3.    Add 
AssetImage as in the 2nd step for Storyboard.
4.    Next, we have to remove information about using the storyboard as our splash screen in Info.plist file. To do that, delete the “Launch screen interface file base name” key.


5.    And then set the appearance of our new splash screen using “Launch Screen” key. “LaunchBackgroundColor” and “LaunchImage” are assets added in a previous steps.


6.    Done. Run the app… and, unfortunately, we can notice a black screen between our beautiful splash screen and the first page of the app.



Android Splash Screen

For Android, we also need our icon image in different resolutions for different devices. In this case, place these images in directories called drawable with different suffixes. If you are not familiar with drawables, I highly recommend reading that article explaining the topic in detail.

To generate all required resolutions of images, I have used the website https://www.img-bak.in/ (but this one is also cool http://romannurik.github.io/AndroidAssetStudio/index.html). Remember to provide high-resolution image as an input, e.g. if you want to use an image of 200x200 pixels in your app, you should provide an image of 800x800 pixels because that is the highest resolution used by some Android devices (drawable-xxxhdpi).

1.    After generating all required images, place them in appropriate directories in Android/app/src/main/res.

2.    Then, we need to modify the Android/app/src/main/res/drawable/launch_background.xml file. This file will represent the look of our splash screen. If you also have a drawable-v21 directory present, which in my case, was generated together with the whole project, you can remove the mentioned directory or place there the same launch_background.xml file as in the drawable directory.

<?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">
<!-- Background color -->
<item>
<color android:color="#2B2A4E" />
</item>
<!-- You can insert your own image assets here -->
<item>
<bitmap
android:gravity="center"
android:src="@drawable/logo" />
</item>
</layer-list>

3.    Next, we have to set our 
launch_background.xml as a splash screen. To do that, open Android/app/src/main/res/values/styles.xml and under LaunchTheme resource set android:windowBackground as in the snippet below.

<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when
Flutter draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your
Flutter UI initializes, as well as behind your Flutter UI while its
running.
This Theme is only used starting with V2 of Flutter's Android embedding. -->
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item>
</style>
</resources>

If you want to have a different splash screen in dark mode/theme, you have to provide a different file e.g.launch_background_dark.xml in values-night/styles.xml.

TIP 2: If you can’t see an icon on your splash screen after building the app, just close the app and open it directly from the device.

Now, if we launch the app on Android 11 or lower, we will see our splash screen, however, on Android 12 and higher, it won’t work in the same way. Android 12 brings some big changes to splash screens. The two most important changes are:

  • the background color must be a single solid color (previously we were able to set any image as a background);
  • the icon must have specific dimensions and be placed in the center of the screen.

More information on that here.

Android 12

Ok, so let’s modify our splash screen for Android 12.

1.    Add a new directory named values-v31. v31 means that this directory will be used instead of the sheer values directory for all Android devices with SDK 31 and higher. Then, place here styles.xml file presented below. Most of the code looks identical to the previous one.

<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when
Flutter draws its first frame -->
<item name="android:windowSplashScreenBackground">#2B2A4E</item>
<item name="android:windowSplashScreenAnimatedIcon">@drawable/android12splash</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your
Flutter UI initializes, as well as behind your Flutter UI while its
running.
This Theme is only used starting with V2 of Flutter's Android embedding. -->
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item>
</style>
</resources>

2.    As I have mentioned earlier, an icon for Android 12 must have some specific dimensions. That is why we use here an image named android12splash instead of logo (which was used earlier in launch_background.xml file as our icon.)

As documentation says:

  • App icon with an icon background: This should be 240×240 dp, and fit within a circle of 160 dp in diameter.
  • App icon without an icon background: This should be 288×288 dp, and fit within a circle of 192 dp in diameter.

To generate all required icons, we can use one of the online tools presented earlier.

For example, first - an icon with wrong dimensions:

and second - with proper ones:

Flutter Splash Screen

flutter_native_splash is a fast way to create a splash screen for both iOS and Android apps. It has some limitations, but in most cases, it is sufficient.

  1. First, we need to add a package to the pubspec.yaml file under dev_dependencies (or under dependencies sometimes 😉`). I am using version 2.1.0.

Most important lines:

  • Line 14 - setting the color of a background. As you can see in the next line, we are also able to set a background image instead of a single color.
  • Line 22 - setting an icon.
  • Line 53 - setting an icon for Android 12 and higher.
  • There is also an option to set different colors and icons depending on dark/light mode/theme and much more, which is well documented and easy to understand.
flutter_native_splash:

# This package generates native code to customize Flutter's default white native splash screen
# with background color and splash image.
# Customize the parameters below, and run the following command in the terminal:
# flutter pub run flutter_native_splash:create
# To restore Flutter's default white splash screen, run the following command in the terminal:
# flutter pub run flutter_native_splash:remove

# color or background_image is the only required parameter. Use color to set the background
# of your splash screen to a solid color. Use background_image to set the background of your
# splash screen to a png image. This is useful for gradients. The image will be stretch to the
# size of the app. Only one parameter can be used, color and background_image cannot both be set.
color: "#2b2a4e"
#background_image: "assets/splash/background.png"

# Optional parameters are listed below. To enable a parameter, uncomment the line by removing
# the leading # character.

# The image parameter allows you to specify an image used in the splash screen. It must be a
# png file and should be sized for 4x pixel density.
image: assets/logo.png

# The branding property allows you to specify an image used as branding in the splash screen.
# It must be a png file. Currently, it is only supported for Android < v12 and iOS.
#branding: assets/dart.png

# To position the branding image at the bottom of the screen you can use bottom, bottomRight,
# and bottomLeft. The default values is bottom if not specified or specified something else.
#branding_mode: bottom

# The color_dark, background_image_dark, image_dark, branding_dark are parameters that set the background
# and image when the device is in dark mode. If they are not specified, the app will use the
# parameters from above. If the image_dark parameter is specified, color_dark or
# background_image_dark must be specified. color_dark and background_image_dark cannot both be
# set.
#color_dark: "#042a49"
#background_image_dark: "assets/dark-background.png"
#image_dark: assets/splash-invert.png
#branding_dark: assets/dart_dark.png

# Android 12 handles the splash screen differently than previous versions. Please visit
# https://developer.android.com/guide/topics/ui/splash-screen
# Following are Android 12 specific parameter.
android_12:
# The image parameter sets the splash screen icon image. If this parameter is not specified,
# the app's launcher icon will be used instead.
# Please note that the splash screen will be clipped to a circle on the center of the screen.
# App icon with an icon background: This should be 960×960 pixels, and fit within a circle
# 640 pixels in diameter.
# App icon without an icon background: This should be 1152×1152 pixels, and fit within a circle
# 768 pixels in diameter.
image: assets/android12splash.png

# App icon background color.
#icon_background_color: "#111111"

# The image_dark parameter and icon_background_color_dark set the image and icon background
# color when the device is in dark mode. If they are not specified, the app will use the
# parameters from above.
#image_dark: assets/android12splash-invert.png
#icon_background_color_dark: "#eeeeee"

# The android, ios and web parameters can be used to disable generating a splash screen on a given
# platform.
#android: false
#ios: false
web: false

# The position of the splash image can be set with android_gravity, ios_content_mode, and
# web_image_mode parameters. All default to center.
#
# android_gravity can be one of the following Android Gravity (see
# https://developer.android.com/reference/android/view/Gravity): bottom, center,
# center_horizontal, center_vertical, clip_horizontal, clip_vertical, end, fill, fill_horizontal,
# fill_vertical, left, right, start, or top.
#android_gravity: center
#
# ios_content_mode can be one of the following iOS UIView.ContentMode (see
# https://developer.apple.com/documentation/uikit/uiview/contentmode): scaleToFill,
# scaleAspectFit, scaleAspectFill, center, top, bottom, left, right, topLeft, topRight,
# bottomLeft, or bottomRight.
#ios_content_mode: center
#
# web_image_mode can be one of the following modes: center, contain, stretch, and cover.
#web_image_mode: center

# To hide the notification bar, use the fullscreen parameter. Has no effect in web since web
# has no notification bar. Defaults to false.
# NOTE: Unlike Android, iOS will not automatically show the notification bar when the app loads.
# To show the notification bar, add the following code to your Flutter app:
# WidgetsFlutterBinding.ensureInitialized();
# SystemChrome.setEnabledSystemUIOverlays([SystemUiOverlay.bottom, SystemUiOverlay.top]);
fullscreen: true
# If you have changed the name(s) of your info.plist file(s), you can specify the filename(s)
# with the info_plist_files parameter. Remove only the # characters in the three lines below,
# do not remove any spaces:
#info_plist_files:
# - 'ios/Runner/Info-Debug.plist'
# - 'ios/Runner/Info-Release.plist'

1.    Then, set the appearance of our splash screen using the 
flutter_native_splash.yaml file.
2.    The last step is to run command flutter pub run flutter_native_splash:create --path=flutter_native_splash.yaml. And that is all!

One more thing to explain, what is the reason to place the flutter_native_splash package under dependencies? With the version 2.0.3+1 the package allows us to select the time when the splash screen should disappear. So now we are able to initialize everything we need to start the app and then show our first screen. Previously, when the app was ready to render the first frame of the app, the native splash screen (so that one we were creating) disappeared and there was a need to create a special page being our splash screen until the whole app was initialized.

So to keep displaying the native splash screen, we need to write two simple lines of code 7-8:

Future<void> main() async {
await initApp();
runApp(const MyApp());
}

initApp() {
WidgetsBinding widgetsBinding = WidgetsFlutterBinding.ensureInitialized();
FlutterNativeSplash.preserve(widgetsBinding: widgetsBinding);
}

After that, the splash screen will be visible until we call ​​FlutterNativeSplash.remove();.

What is under the hood?

Let’s check what changes the flutter_native_splash package makes to our project after running the generate command.

iOS changes


Info.plist - setting a flag to hide status bar during splash screen.


ios/Runner/Assets.xcassets/BrandingImage.imageset/* - directory for setting branding image at the bottom of the splash screen. We didn’t set that in our config file flutter_native_splash.yaml, but it was generated anyway. So we can remove that whole directory BrandingImage.imageset.

ios/Runner/Assets.xcassets/BackgroundImage.imageset/background.image - this package uses a storyboard to set a splash screen for iOS. In storyboard, it sets background as an image. So firstly, the package generates an asset image (1x1 pixel) which represents a background color and then sets it as a background image.

ios/Runner/Assets.xcassets/LaunchImage.imageset/* - directory for icon (“logo.png”) automatically generated in different resolutions.

ios/Runner/Base.lproj/LaunchScreen.storyboard - as I have mentioned earlier, the package uses storyboard in which icon and background color is being set.

Android changes



All files named android12splash.png are generated images for different devices with Android 12 and higher placed in appropriate drawable directories.

All files named logo.png are generated images for different devices with Android 11 and lower placed in appropriate drawable directories.

background.png - image 1x1 pixel which represents a background color. This file is later used in the launch_background.xml file to set the background.

launch_background.xml - the same file we have been modifying earlier, when setting the splash screen without a package, but with some changes.

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<bitmap android:gravity="fill" android:src="@drawable/background"/>
</item>
<item>
<bitmap android:gravity="center" android:src="@drawable/splash"/>
</item>
</layer-list>

In drawable and drawable-v21 directories, we have exactly the same files, so we can remove the latter one if we want.

android/app/src/main/res/values/styles.xml - again, the same file we have been modifying earlier with some differences i.e. added two flags forceDarkAllowed and windowFullscreen.

So as you can see, there is no magic. flutter_native_splash Package does everything that we can do ourselves, but faster 😊.

Comments

Popular posts from this blog

How To Change Value In Appbar Text Flutter On Button Click From Other class

  How to Update State of Parent StatefulWidget from other Child StatefulWidget in Flutter? Hi! all today we going to learn how we can update or change text of parent StatefulWidget in appbar from the child StatefulWidget in flutter. Same as we can also change any color, icon or other data of parent widget. class ParentWidget extends StatelessWidget {    int cartitem = 0 ; @override Widget build ( BuildContext context) { return Scaffold ( appBar: AppBar ( titleSpacing: 0 , leading: Icon ( Icons .location_on, size: 20 , color: Colors .white, ), title: Text ( "Title" ), actions: < Widget >[ Stack ( children: [ IconButton ( icon: Icon ( Icons .shopping_cart), color: Colors .white, ), Positioned . directional ( textDirection: Directionality . of (context), ...