You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter AnimatedSplashScreen显示白屏问题求助

问题:使用AnimatedSplashScreen组件出现白屏

应用运行时AnimatedSplashScreen显示白屏,截图如下:
AnimatedSplashScreen白屏截图

SplashScreen类代码:

class SplashScreen extends StatelessWidget {
  const SplashScreen({super.key});

  @override
  Widget build(BuildContext context) {
    final user = AuthService().currentUser;
    String nextScreen =
        user != null ? RoutesEnum.homePage : RoutesEnum.loginPage;

    return AnimatedSplashScreen(
      duration: 1500,
      splash: Icons.home,
      nextScreen: LoginPage(),
      nextRoute: nextScreen,
      splashTransition: SplashTransition.rotationTransition,
    );}}

main.dart代码:

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();
  runApp(MaterialApp(
  debugShowCheckedModeBanner: false,
  theme: mainTheme,
  home: const SplashScreen(),
  routes: {
    //RoutesEnum.splashScreen: (context) => const SplashScreen(),
    RoutesEnum.loginPage: (context) => LoginPage(),
    RoutesEnum.signUpPage: (context) => SignUpPage(),
    RoutesEnum.homePage: (context) => HomePage(),
  },
  ));
  }

补充:LoginPage代码

class LoginPage extends StatefulWidget {
  @override
  _LoginPageState createState() => _LoginPageState();
}

class _LoginPageState extends State<LoginPage> {
  final authService = AuthService();

  final emailcon = TextEditingController();
  final passwordcon = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      resizeToAvoidBottomInset: false,
      body: Stack(
        children: [
          Padding(
            padding: const EdgeInsets.all(12),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.center,
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                Image.asset(
                  "assets/images/Logo_ohne_Hintergrund.png",
                  color: Colors.white.withOpacity(0.75),
                  colorBlendMode: BlendMode.modulate,
                ),
                addVerticalSpace(60),
                addFormEmailPassword(emailcon, passwordcon),
                addVerticalSpace(20),
                RoundButton(
                  title: "Login",
                  tapfun: () => {
                    if (emailcon.text.toString().isEmpty ||
                        passwordcon.text.toString().isEmpty)
                      {
                        toastmessage("Eingaben prüfen"),
                      }
                    else
                      {
                        authService
                            .signInWithEmailAndPassword(
                              email: emailcon.text.toString(),
                              password: passwordcon.text.toString(),
                            )
                            .then(
                              (value) => {
                                if (value)
                                  {
                                    Navigator.pushReplacementNamed(
                                      context,
                                      RoutesEnum.homePage,
                                    ),
                                  }
                              },
                            ),
                      }
                  },
                ),
                addVerticalSpace(20),
                const Text("- OR -"),
                addVerticalSpace(20),
                GoogleAuthButton(
                  style: AuthButtonStyle(
                    buttonType: AuthButtonType.icon,
                    buttonColor: Theme.of(context).backgroundColor,
                    borderRadius: 25,
                  ),
                  onPressed: () => {
                    authService.signInWithGoogle().then(
                          (value) => {
                            Navigator.pushReplacementNamed(
                              context,
                              RoutesEnum.homePage,
                            ),
                          },
                        ),
                  },
                ),
                addVerticalSpace(20),
                RoundButton(
                  title: "Toast",
                  tapfun: () {
                    toastmessage(
                      authService.currentUser == null
                          ? "NULL"
                          : authService.currentUser!.email.toString(),
                    );
                  },
                ),
              ],
            ),
          ),
          Padding(
            padding: const EdgeInsets.all(30),
            child: Align(
              alignment: Alignment.bottomCenter,
              child: Row(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  const Text(
                    "Don't have an account?",
                    style: TextStyle(
                      color: Colors.white,
                    ),
                  ),
                  TextButton(
                    onPressed: () {
                      Navigator.pushNamed(
                        context,
                        RoutesEnum.signUpPage,
                      );
                    },
                    child: const Text("Sign Up"),
                  ),
                ],
              ),
            ),
          )
        ],
      ),
    );
  }
}

请问我哪里出错了?


解决方案

白屏问题主要由两个核心问题导致:

1. 参数冲突:同时设置nextScreen和nextRoute

AnimatedSplashScreen组件中,nextScreen(直接指定跳转Widget)和nextRoute(指定命名路由)是互斥的,不能同时设置。你当前同时传递了这两个参数,导致组件路由逻辑冲突,引发白屏。

2. 用户状态判断时机过早

在StatelessWidget的build方法中直接获取AuthService().currentUser,此时Firebase Auth可能还未完成初始化,拿到的用户状态不准确;且build方法会被多次调用,容易导致路由跳转逻辑混乱。


修复步骤:

步骤1:移除冲突参数

保留nextRoute(符合你使用命名路由的逻辑),删除nextScreen: LoginPage(),这一行:

return AnimatedSplashScreen(
  duration: 1500,
  splash: Icons.home,
  nextRoute: nextScreen, // 仅保留该参数
  splashTransition: SplashTransition.rotationTransition,
);

步骤2:异步处理用户状态判断

将SplashScreen改为StatefulWidget,在initState中异步获取用户状态,确保Firebase Auth初始化完成:

class SplashScreen extends StatefulWidget {
  const SplashScreen({super.key});

  @override
  State<SplashScreen> createState() => _SplashScreenState();
}

class _SplashScreenState extends State<SplashScreen> {
  late String _nextScreen;

  @override
  void initState() {
    super.initState();
    _determineNextScreen();
  }

  Future<void> _determineNextScreen() async {
    // 等待Firebase Auth初始化完成,确保用户状态准确
    await Future.delayed(const Duration(milliseconds: 500));
    final user = AuthService().currentUser;
    setState(() {
      _nextScreen = user != null ? RoutesEnum.homePage : RoutesEnum.loginPage;
    });
  }

  @override
  Widget build(BuildContext context) {
    return AnimatedSplashScreen(
      duration: 1500,
      splash: Icons.home,
      nextRoute: _nextScreen,
      splashTransition: SplashTransition.rotationTransition,
    );
  }
}

步骤3:可选:添加背景色区分白屏

检查你的mainTheme是否设置了合适的背景色,如果主题背景为白色,可给AnimatedSplashScreen添加backgroundColor参数,避免启动图标与背景融合导致视觉上的白屏:

return AnimatedSplashScreen(
  duration: 1500,
  splash: Icons.home,
  nextRoute: _nextScreen,
  splashTransition: SplashTransition.rotationTransition,
  backgroundColor: Colors.blue, // 设置启动页背景色
);

完成以上修改后,即可解决白屏问题,正常显示启动动画并跳转到对应页面。

内容的提问来源于stack exchange,提问作者Anton Schrage

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 08:11:40