Flutter中如何存储ThemeData以保证应用重启后自定义主题不丢失
问题根本原因
你当前的主题列表toReturnTheme只存储在应用运行时的内存中,应用进程被销毁(重启、后台被清理)后内存数据会被清空,所以新增的自定义主题会消失。
实现思路
不需要完整序列化ThemeData对象(复杂度高易出错),只需要存储自定义主题用到的核心配置参数,应用启动时读取这些参数再动态生成ThemeData加入列表即可,使用官方的shared_preferences库做本地轻量存储即可满足需求。
具体实现步骤
1. 引入依赖
在pubspec.yaml中添加依赖:
dependencies: flutter: sdk: flutter shared_preferences: ^2.2.2 # 可替换为最新稳定版本
执行flutter pub get安装依赖。
2. 新建自定义主题配置模型
用来封装需要存储的主题参数,实现Json序列化/反序列化:
import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:shared_preferences/shared_preferences.dart'; class CustomThemeConfig { final int scaffoldBackgroundColor; final int backgroundColor; final int buttonColor; final int accentColor; final int fabBackgroundColor; final int fontColor; final String themeName; CustomThemeConfig({ required this.scaffoldBackgroundColor, required this.backgroundColor, required this.buttonColor, required this.accentColor, required this.fabBackgroundColor, required this.fontColor, required this.themeName, }); // 转为Json格式 Map<String, dynamic> toJson() { return { 'scaffoldBackgroundColor': scaffoldBackgroundColor, 'backgroundColor': backgroundColor, 'buttonColor': buttonColor, 'accentColor': accentColor, 'fabBackgroundColor': fabBackgroundColor, 'fontColor': fontColor, 'themeName': themeName, }; } // 从Json生成配置对象 factory CustomThemeConfig.fromJson(Map<String, dynamic> json) { return CustomThemeConfig( scaffoldBackgroundColor: json['scaffoldBackgroundColor'] as int, backgroundColor: json['backgroundColor'] as int, buttonColor: json['buttonColor'] as int, accentColor: json['accentColor'] as int, fabBackgroundColor: json['fabBackgroundColor'] as int, fontColor: json['fontColor'] as int, themeName: json['themeName'] as String, ); } // 配置转为ThemeData对象 ThemeData toThemeData() { return ThemeData( scaffoldBackgroundColor: Color(scaffoldBackgroundColor), backgroundColor: Color(backgroundColor), buttonColor: Color(buttonColor), accentColor: Color(accentColor), floatingActionButtonTheme: FloatingActionButtonThemeData( backgroundColor: Color(fabBackgroundColor), ), textTheme: TextTheme( bodyText2: TextStyle(color: Color(fontColor), fontFamily: 'Muli'), bodyText1: TextStyle(color: Color(fontColor), fontFamily: themeName), ), ); } // 存储自定义主题列表到本地 static Future<void> saveCustomThemes(List<CustomThemeConfig> themes) async { final prefs = await SharedPreferences.getInstance(); final jsonList = themes.map((e) => jsonEncode(e.toJson())).toList(); await prefs.setStringList('custom_themes', jsonList); } // 从本地读取自定义主题列表 static Future<List<CustomThemeConfig>> getCustomThemes() async { final prefs = await SharedPreferences.getInstance(); final jsonList = prefs.getStringList('custom_themes') ?? []; return jsonList.map((e) => CustomThemeConfig.fromJson(jsonDecode(e))).toList(); } }
3. 修改主题加载逻辑
修改getThemes方法,启动时加载本地存储的自定义主题:
List<ThemeData> toReturnTheme = <ThemeData>[]; Future<List<ThemeData>> getThemes() async { // 先清空原有列表,避免重复添加 toReturnTheme.clear(); // 添加预置默认主题 ThemeData szikraTheme = ThemeData( scaffoldBackgroundColor: const Color(0xff5a89ba), backgroundColor: const Color(0xff5a89b0), buttonColor: const Color(0xfff78848), accentColor: Colors.white, floatingActionButtonTheme: const FloatingActionButtonThemeData( backgroundColor: Color(0xff3a89ba), ), textTheme: const TextTheme( bodyText2: TextStyle(color: Colors.white, fontFamily: 'Muli'))); ThemeData cobotTheme = ThemeData( scaffoldBackgroundColor: const Color(0xff207ABB), backgroundColor: const Color(0xff207ABB), buttonColor: const Color(0xfff78848), accentColor: Colors.white, floatingActionButtonTheme: const FloatingActionButtonThemeData( backgroundColor: Color(0xff3a89ba), ), textTheme: const TextTheme( bodyText2: TextStyle(color: Colors.white, fontFamily: 'Muli'))); toReturnTheme.add(szikraTheme); toReturnTheme.add(cobotTheme); // 加载本地存储的自定义主题 final customConfigs = await CustomThemeConfig.getCustomThemes(); for (var config in customConfigs) { toReturnTheme.add(config.toThemeData()); } return toReturnTheme; }
注意这个方法变成异步方法,需要在应用启动的合适位置(比如初始化页、main函数初始化阶段)先等待它执行完成再渲染主题相关界面。
4. 实现主题持久化方法
把你代码中未实现的saveTheme方法替换为如下实现,新增主题时同步存储到本地:
Future<void> saveTheme() async { // 提取所有自定义主题(前两个是预置默认主题无需存储) final customThemes = toReturnTheme.sublist(2); List<CustomThemeConfig> configs = []; for (var theme in customThemes) { configs.add(CustomThemeConfig( scaffoldBackgroundColor: theme.scaffoldBackgroundColor.value, backgroundColor: theme.backgroundColor.value, buttonColor: theme.buttonColor.value, accentColor: theme.accentColor.value, fabBackgroundColor: theme.floatingActionButtonTheme.backgroundColor!.value, fontColor: theme.textTheme.bodyText1!.color!.value, themeName: theme.textTheme.bodyText1!.fontFamily ?? "自定义主题", )); } await CustomThemeConfig.saveCustomThemes(configs); }
5. 修改删除主题逻辑
你的ListView中删除主题的逻辑要同步更新本地存储,避免删除的主题重启后恢复:
onTap: () { toReturnTheme.removeAt(index); // 同步更新本地存储 saveTheme(); setState(() {}); },
内容的提问来源于stack exchange,提问作者KrekZsole
相关产品推荐
相关产品推荐

