M Muiz Hassan
Posted on May 30, 2021
Hi, I hope you all are doing great. In this tutorial I'll be sharing the technique I use to make a quick and interactive splash screen in flutter.
Prerequisites
- Basic knowledge of flutter
- Basic knowledge of android
Overview
In some cases we want to add an interactive splash screen to our app to prompt the user for different states, such as no internet connection. But just creating a splash widget may not be as satisfactory because flutter takes some time to draw its first frame when the app is launched. So today we'll be combining flutter splash screen with native android splash to get a quick and interactive splash screen.
Let's Get Started
Flutter Side
1. Create a new flutter project and open it in an IDE of your choice.
2. Go to the pubspec.yaml file and specify the assets directory as following:
flutter:
# ... other properties here
assets:
- assets/images/
Also change the dart SDK version constraints to enable null safety:
environment:
sdk: ">=2.12.0 <3.0.0"
3. Create a folder assets
in the project root directory. And paste this image as "logo_flutter.png" in it.
4. Create a new dart file "splash_page.dart" in the "lib" folder and paste the following code in it:
import 'package:flutter/material.dart';
class SplashPage extends StatefulWidget {
@override
_SplashPageState createState() => _SplashPageState();
}
class _SplashPageState extends State<SplashPage> {
@override
void initState() {
WidgetsBinding.instance?.addPostFrameCallback((_) => _afterBuild(context));
super.initState();
}
@override
Widget build(BuildContext context) {
return Container(
color: Colors.white,
child: Center(
child: Image.asset('assets/images/logo_flutter.png'),
),
);
}
void _afterBuild(BuildContext context) {
showModalBottomSheet(
context: context,
isDismissible: false,
enableDrag: false,
barrierColor: Colors.transparent,
backgroundColor: Colors.blue,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: const Radius.circular(25),
topRight: const Radius.circular(25),
)),
builder: (builderContext) {
return SizedBox(
height: 100,
child: Padding(
padding: EdgeInsets.all(16),
child: Center(
child: ElevatedButton(
style: ElevatedButton.styleFrom(
primary: Colors.white,
onPrimary: Colors.blue,
),
onPressed: () => Navigator.pop(context),
child: Text('Dismiss'),
),
),
),
);
},
);
}
}
In the above code, we schedule our _afterBuild
method to be called after the build
method, inside the initState
callback. The _afterBuild
method will display a modal bottom sheet after the splash page has been drawn. Which can be dismissed by pressing the dismiss button.
5. Go to main.dart file and replace the existing code with following.
import 'package:flutter/material.dart';
import 'splash_page.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter App',
debugShowCheckedModeBanner: false,
home: SplashPage(),
);
}
}
The SplashPage
widget has been passed as the home
parameter, meaning flutter will show the SplashPage
when our app is launched.
Android Side
6. For the android side we will need to create resolution aware image assets for our splash logo. Open the Image Baker website in your browser. Drop the the "logo_flutter.png" image you downloaded earlier. The site will generate the assets for you. Go ahead and download them by clicking on the Android button.
7. Extract the folder somewhere and you will find several drawable folders inside the extracted folder. These folders tell android which asset to use for different density displays. Copy all the drawable folders and paste them inside the {your_project}/android/app/src/main/res
folder.
8. Now we need to tell android to use our newly added asset. Open the "launch_background.xml" file in the "res/drawable" folder and replace the contents with following:
<?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>
<bitmap
android:gravity="center"
android:src="@drawable/logo_flutter" />
</item>
</layer-list>
Make sure you are using the correct drawable resource name. Flutter creates a drawable-v21 variant by default for "launch_background.xml". If you don't need it for anything else delete the drawable-v21 folder or the "launch_background.xml" in it.
9. Now that we have added all the assets we need to make sure that the splash image size for our flutter splash and native android splash is the same. Open "logo_flutter.png" inside the res/drawable-xxxhdpi folder. Note the size of the image, we will need our flutter splash image to match the size of this image.
For xxxhdpi an image of 640px will be drawn as 1 inch on the device screen, while for flutter an image of 160 logical pixels will occupy 1 physical inch.
So we can calculate the size needed for flutter splash with the following equation:
h = (height of the xxxhdpi image) / 640 * 160
Where h
is the calculated height for the flutter splash image. Go to "splash_page.dart" and add the calculated height to the image.
@override
Widget build(BuildContext context) {
return Container(
color: Colors.white,
child: Center(
child: Image.asset(
'assets/images/logo_flutter.png',
height: 168.94, // calculated height in my case
),
),
);
}
Conclusion
And that's it we're done. Go ahead and run the application to watch your custom splash screen in action! Now we can discuss the pros and cons of this approach.
Pros
You get an instantaneous splash screen that is visible the moment your app launches. The splash becomes interactive when the flutter splash widget is drawn.
Cons
There is a slight blink when flutter draws its first frame. The lag is unacceptably long in development mode but it turns to only a slight blink in release mode. You can try to further optimize your flutter splash image by using resolution aware image assets.
That concludes this tutorial. I have hosted an example project on GitHub for anyone who is interested. I can't wait to see your feedback in the comments below. I hope to see you folks next time with more interesting content.
Posted on May 30, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.