smooth transition from native splash sceen to an animated page - how to do?
I am working on a Flutter app for both Android and iOS, and I'm using the flutter_native_splash plugin to create a static splash screen. However, my client wants an animated splash screen immediately following the static one. The plugin doesn't support animations directly, so we agreed on a setup where a static splash screen is displayed first, followed by a custom animated splash screen built within Flutter.
The static splash screen is set up with flutter_native_splash, which scales the image to fit different device screens, but I'm unsure how to perfectly align the image size of the animated splash screen to match the static one.
What are the best practices to synchronize the image dimensions between the static image used by flutter_native_splash and the subsequent animated image in Flutter?
is this even possible? any advice - I will be very grateful
@FetFrumos have you found a way to sync the static and dynamic images ?
I thought we could discuss how we could contribute to this open source project, haha^^
Same! My client want a "fade in/out" animation
This should be an easy one - at least a fade out on calling FlutterNativeSplash.remove(); right?
Well maybe not - have you checke the code in - https://github.com/jonbhanson/flutter_native_splash/blob/master/lib/flutter_native_splash.dart ? This seems like it only prevents the first frame to draw - so to make a smooth animation, we would need to find the currently displayed image and fade away. Have you tried with a dynamic screenshot maybe?
@BriceFab How did you eventually solve this problem? Thank you.
@FetFrumos @CHUNG-HAO
I have maybe found a solution but :
- not tested on devices with devicePixelRatio != 3
- on Android >= 12 there is a slide out + fade out transition on the native splash and I don't know how to prevent this
Create 2 splash images, one for iOS and Android < 12 and another one for Android >= 12 :
- assets/images/splash.png : 1440x1440 for iOS and Android < 12
- assets/images/splash_android12.png : 1080x1080 for Android >= 12
Here is an explanation on how you have to export your images :
| assets/images/splash.png | assets/images/splash_android12.png |
|---|---|
Change your pubspec.yaml to :
dependencies:
device_info_plus: 10.1.2
...
flutter_native_splash:
color: "#FFFFFF"
image: assets/images/splash/image.png
fullscreen: false
web: false
ios: true
info_plist_files:
- ios/Runner/Info-Debug.plist
- ios/Runner/Info-Release.plist
android: true
android_12:
color: "#FFFFFF"
image: assets/images/splash/image_android12.png
icon_background_color: "#FFFFFF"
Do not forget to generate splash using dart run flutter_native_splash:create
Create your splash route :
class RouteAppSplash extends StatefulWidget {
const RouteAppSplash({super.key});
@override
State<RouteAppSplash> createState() => _RouteAppSplashState();
}
class _RouteAppSplashState extends State<RouteAppSplash> {
final _completer = Completer();
var _logoImage = '';
var _logoScale = 1.0;
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((timestamp) {
// replace native splash by the custom one
// scale and image are computed based on device
_hydrate();
_completer.future.then((_) async {
// * 1. run your animation
// * 2. redirect to your main screen
});
});
}
Future<void> _hydrate() async {
if (Platform.isIOS) {
_logoImage = 'assets/images/splash.png'; // 1440x1440
_logoScale = 360 / MediaQuery.sizeOf(context).width; // @1x width divided by logical screen width
} else if (Platform.isAndroid) {
final deviceInfo = DeviceInfoPlugin();
final androidInfo = await deviceInfo.androidInfo;
final version = int.tryParse(androidInfo.version.release ?? '') ?? 0;
if (version >= 12) {
_logoImage = 'assets/images/splash_android12.png'; // 1080x1080
_logoScale = .75;
} else if (Platform.isAndroid) {
_logoImage = 'assets/images/splash.png'; // 1440x1440
_logoScale = 1;
}
}
if (mounted) {
await precacheImage(AssetImage(_logoImage), context); // precache to avoid blink
}
setState(() {});
FlutterNativeSplash.remove(); // remove native splash
_completer.complete(); // notify that custom splash is displayed
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: Center(
child: Transform.scale(
scale: _logoScale,
child: Image.asset(
_logoImage,
fit: BoxFit.cover,
),
),
),
);
}
}
@ziadsarour It's a little unclear where you got the FlutterNativeSplash.remove() line from. Is this a custom static method? And how did you manage to avoid the slide-out + smooth disappear transition on the native splash screen in the ios system? On the ios emulator this transition is still present
@FetFrumos @CHUNG-HAO
I have maybe found a solution but :
- not tested on devices with devicePixelRatio != 3
- on Android >= 12 there is a slide out + fade out transition on the native splash and I don't know how to prevent this
Create 2 splash images, one for iOS and Android < 12 and another one for Android >= 12 :
- assets/images/splash.png : 1440x1440 for iOS and Android < 12
- assets/images/splash_android12.png : 1080x1080 for Android >= 12
Here is an explanation on how you have to export your images :
Change your
pubspec.yamlto :dependencies: device_info_plus: 10.1.2 ... flutter_native_splash: color: "#FFFFFF" image: assets/images/splash/image.png fullscreen: false web: false ios: true info_plist_files: - ios/Runner/Info-Debug.plist - ios/Runner/Info-Release.plist android: true android_12: color: "#FFFFFF" image: assets/images/splash/image_android12.png icon_background_color: "#FFFFFF"Do not forget to generate splash using
dart run flutter_native_splash:createCreate your splash route :
class RouteAppSplash extends StatefulWidget { const RouteAppSplash({super.key}); @override State<RouteAppSplash> createState() => _RouteAppSplashState(); } class _RouteAppSplashState extends State<RouteAppSplash> { final _completer = Completer(); var _logoImage = ''; var _logoScale = 1.0; @override void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((timestamp) { // replace native splash by the custom one // scale and image are computed based on device _hydrate(); _completer.future.then((_) async { // * 1. run your animation // * 2. redirect to your main screen }); }); } Future<void> _hydrate() async { if (Platform.isIOS) { _logoImage = 'assets/images/splash.png'; // 1440x1440 _logoScale = 360 / MediaQuery.sizeOf(context).width; // @1x width divided by logical screen width } else if (Platform.isAndroid) { final deviceInfo = DeviceInfoPlugin(); final androidInfo = await deviceInfo.androidInfo; final version = int.tryParse(androidInfo.version.release ?? '') ?? 0; if (version >= 12) { _logoImage = 'assets/images/splash_android12.png'; // 1080x1080 _logoScale = .75; } else if (Platform.isAndroid) { _logoImage = 'assets/images/splash.png'; // 1440x1440 _logoScale = 1; } } if (mounted) { await precacheImage(AssetImage(_logoImage), context); // precache to avoid blink } setState(() {}); FlutterNativeSplash.remove(); // remove native splash _completer.complete(); // notify that custom splash is displayed } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.white, body: Center( child: Transform.scale( scale: _logoScale, child: Image.asset( _logoImage, fit: BoxFit.cover, ), ), ), ); } }
if this stuff works should be part of the package
@ziadsarour It's a little unclear where you got the FlutterNativeSplash.remove() line from. Is this a custom static method? And how did you manage to avoid the slide-out + smooth disappear transition on the native splash screen in the ios system? On the ios emulator this transition is still present
FlutterNativeSplash.remove() is part of the package.
I don't have (and never had) a slide-out + smooth disappear transition on iOS, it might be due to your code/configuration