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

Flutter如何加载多个Future 解决主题配置在界面渲染后才生效问题

问题根源

你当前的主题配置是在CustomTheme实例化后异步加载的,runApp执行时主题用的是默认的isDarkTheme = false值,等异步加载完偏好设置才会触发重绘,就会出现界面渲染完成后才切换主题的问题。FutureBuilder是Flutter组件,不能在非Widget的theme.dart逻辑文件里直接使用。

解决步骤

1. 修改theme.dart,新增可等待的初始化方法

把加载偏好设置的逻辑改成可等待的Future,方便在启动阶段提前执行:

import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';

CustomTheme customTheme = CustomTheme();

class CustomTheme extends ChangeNotifier {
  // 移除static修饰,避免状态监听异常
  bool isDarkTheme = false;

  ThemeData get currentTheme => isDarkTheme
      ? ThemeData(
          brightness: Brightness.dark,
          scaffoldBackgroundColor: Colors.grey.shade900,
          primaryColor: Colors.white,
          accentColor: Colors.blue,
          iconTheme: const IconThemeData(color: Colors.white, opacity: 0.8),
        )
      : ThemeData(
          brightness: Brightness.light,
          scaffoldBackgroundColor: Colors.white,
          primaryColor: Colors.black,
          accentColor: Colors.blue,
          iconTheme: const IconThemeData(color: Colors.black, opacity: 0.8),
          dividerColor: Colors.black12,
        );

  // 新增异步初始化方法,提前加载主题配置
  Future<void> initTheme() async {
    await loadPrefs();
  }

  void toggleTheme() {
    isDarkTheme = !isDarkTheme;
    savePrefs();
    notifyListeners();
  }

  void savePrefs() async {
    SharedPreferences _prefs = await SharedPreferences.getInstance();
    _prefs.setBool('theme', isDarkTheme);
  }

  Future<void> loadPrefs() async {
    SharedPreferences _prefs = await SharedPreferences.getInstance();
    isDarkTheme = _prefs.getBool('theme') ?? false;
    notifyListeners();
  }
}

2. 修改main.dart,合并邮箱和主题的加载逻辑

把两类配置的加载合并成一个Future,等所有配置加载完成再渲染业务界面,避免主题切换闪烁:

import 'package:chatapp/home.dart';
import 'package:chatapp/login.dart';
import 'package:chatapp/themes.dart';
import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:shared_preferences/shared_preferences.dart';

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();
  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
  // 合并两个异步加载任务:读取邮箱配置 + 读取主题配置
  Future<Map<String, dynamic>> loadAllConfigs() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    String email = prefs.getString('email') ?? '';
    // 等待主题配置加载完成
    await customTheme.initTheme();
    return {'email': email};
  }

  @override
  void initState() {
    super.initState();
    customTheme.addListener(() {
      setState(() {});
    });
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: customTheme.currentTheme,
      // 基于合并后的Future做渲染判断,所有配置加载完成后再进入业务页
      home: FutureBuilder<Map<String, dynamic>>(
        future: loadAllConfigs(),
        builder: (BuildContext context, AsyncSnapshot<Map<String, dynamic>> snapshot) {
          if (snapshot.connectionState == ConnectionState.waiting) {
            return Scaffold(
              body: Center(
                child: CircularProgressIndicator(),
              ),
            );
          } else if (snapshot.connectionState == ConnectionState.done) {
            if (snapshot.hasError) {
              return const Text('Error');
            } else if (snapshot.hasData && snapshot.data!['email'].isNotEmpty) {
              return Home();
            } else {
              return Login();
            }
          } else {
            return Text('State: ${snapshot.connectionState}');
          }
        },
      ),
    );
  }
}

实现原理

现在邮箱、主题两类配置都会在启动加载阶段全部读取完成,等主题配置已经赋值后才会渲染首页/登录页,完全避免了界面渲染后再切换主题的问题。如果想要进一步提升启动速度,也可以把主题初始化逻辑放到main函数里await Firebase.initializeApp()的后面同步等待,效果完全一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 19:45:03