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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 08:24:01