Flutter应用启动出现黑白屏、SplashScreen加载延迟问题如何修复
Flutter启动黑白屏与SplashScreen加载过慢修复方案
1. 解决启动初始黑白屏问题
该黑白屏是Flutter引擎初始化完成前,系统默认展示的原生占位页,和你写的Flutter层SplashScreen无关,必须通过修改原生端配置修复:
- 安卓端:修改
android/app/src/main/res/drawable/launch_background.xml文件(没有就新建),配置和你SplashScreen一致的蓝色背景、logo资源,示例代码:
<?xml version="1.0" encoding="utf-8"?> <layer-list xmlns:android="http://schemas.android.com/apk/res/android"> <item android:drawable="@android:color/blue" /> <item> <bitmap android:gravity="center" android:src="@mipmap/logo" /> <!-- 把logo放到对应mipmap目录下 --> </item> </layer-list>
- iOS端:用Xcode打开项目的
ios/Runner.xcworkspace,修改LaunchScreen.storyboard,设置背景色为蓝色,添加居中展示的logo,和SplashScreen样式保持一致。
修改后原生启动页和Flutter层SplashScreen完全衔接,不会再出现黑白屏过渡。
2. 优化SplashScreen加载速度
- 图片预缓存:在main函数初始化完成
WidgetsFlutterBinding后,提前预缓存Splash用的logo图片,减少首次加载解码耗时:
void main() async { WidgetsFlutterBinding.ensureInitialized(); // 提前预缓存启动页图片 await precacheImage(const AssetImage('assets/images/logo.png'), WidgetsBinding.instance.rootElement!); // 你原来的其他初始化逻辑 }
- 优化SplashScreen控件树:去掉多余的Scaffold层级,直接用Container承载内容,减少渲染开销,同时给Image.asset指定
cacheWidth、cacheHeight,避免大图解码浪费性能,优化后的Splash代码参考:
import 'package:cms/Configs/app_constants.dart'; import 'package:flutter/material.dart'; class Splashscreen extends StatelessWidget { const Splashscreen({super.key}); @override Widget build(BuildContext context) { return Container( color: Colors.blue, child: Center( child: IsSplashOnlySolidColor == true ? const CircularProgressIndicator( valueColor: AlwaysStoppedAnimation<Color>(Colors.blue), ) : Image.asset( 'assets/images/logo.png', fit: BoxFit.cover, // 改为你的logo实际展示的宽高,单位为像素 cacheWidth: 200, cacheHeight: 200, ), ), ); } }
- 删掉重复初始化代码:你main函数里两次调用了
WidgetsFlutterBinding.ensureInitialized(),保留一次即可,减少不必要的性能消耗。
3. 调整初始化逻辑,避免Splash展示过晚
你当前的代码逻辑是串行执行locale加载、Firebase初始化、SharedPreferences加载,且初始化过程中先展示其他空白进度条控件,到一半才加载SplashScreen,导致用户感知Splash出的很慢。建议调整为:
- 用
Future.wait并行执行所有异步初始化操作(locale获取、Firebase初始化、SharedPreferences实例获取),总耗时直接减少为最长单个异步任务的耗时。 - 最外层优先展示SplashScreen,所有初始化操作在后台并行执行,完成后再跳转对应页面,不要嵌套多层FutureBuilder串行加载。
示例逻辑参考:
// 合并所有异步初始化任务 Future<List<dynamic>> _initAll() async { return Future.wait([ getLocale(), Firebase.initializeApp(), SharedPreferences.getInstance(), ]); } // build方法最外层优先展示Splash,初始化完成再切换内容 @override Widget build(BuildContext context) { return FutureBuilder( future: _initAll(), builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.done && snapshot.hasData) { final locale = snapshot.data![0] as Locale; final prefs = snapshot.data![2] as SharedPreferences; // 初始化完成返回主页/业务逻辑页 return MultiProvider( // 你的provider配置 child: MaterialApp( // 你的app配置 home: Homepage(prefs: prefs), ), ); } // 初始化过程全程展示Splash,不会出现其他空白控件 return MaterialApp( debugShowCheckedModeBanner: false, home: const Splashscreen(), ); }, ); }
内容的提问来源于stack exchange,提问作者UDAY KOL
相关产品推荐
相关产品推荐

