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

Flutter应用:如何保存按钮位置与绘图至手机内存并恢复状态?

解决Flutter应用状态持久化:保存自定义按钮位置与绘图内容

为什么SharedPreferences不适用?

SharedPreferences仅适合存储简单键值对(字符串、布尔值、基础数值),但你的需求涉及复杂对象(按钮位置数组)和绘图内容(路径/像素数据),用它会面临序列化繁琐、存储效率低的问题,因此需要更适配的方案。

方案一:本地文件存储(自定义序列化)

直接将数据序列化为JSON或二进制写入本地文件,适合结构化数据和中等大小内容:

1. 处理按钮位置(List)

先把Offset列表转成可序列化的JSON结构:

// 序列化按钮位置
List<Map<String, double>> serializeButtons(List<Offset> positions) {
  return positions.map((offset) => {
    'dx': offset.dx,
    'dy': offset.dy,
  }).toList();
}

// 反序列化恢复按钮位置
List<Offset> deserializeButtons(List<dynamic> jsonList) {
  return jsonList.map((json) => Offset(
    json['dx'] as double,
    json['dy'] as double,
  )).toList();
}

2. 处理绘图内容(以Path集合为例)

序列化Path的控制点,还原时重建路径:

// 序列化Path(简化版,复杂路径需扩展指令解析逻辑)
List<Map<String, dynamic>> serializePaths(List<Path> paths) {
  return paths.map((path) {
    final metrics = path.computeMetrics();
    final segments = <Map<String, dynamic>>[];
    for (final metric in metrics) {
      final segment = metric.extractPath(0, metric.length);
      segments.add({'points': segment.toJson()}); // 实际需根据Path指令自定义序列化
    }
    return {'segments': segments};
  }).toList();
}

// 反序列化恢复Path
List<Path> deserializePaths(List<dynamic> jsonList) {
  return jsonList.map((json) {
    final path = Path();
    final segments = json['segments'] as List;
    for (final seg in segments) {
      path.addPath(Path.fromJson(seg['points']), Offset.zero);
    }
    return path;
  }).toList();
}

3. 写入/读取本地文件

结合path_provider获取应用私有目录,用dart:io操作文件:

import 'dart:convert';
import 'dart:io';
import 'package:path_provider/path_provider.dart';

// 获取应用文档目录路径
Future<String> get _localDirPath async {
  final dir = await getApplicationDocumentsDirectory();
  return dir.path;
}

Future<File> get _stateFile async {
  final path = await _localDirPath;
  return File('$path/app_state.json');
}

// 保存应用状态
Future<File> saveAppState(List<Offset> buttons, List<Path> drawings) async {
  final file = await _stateFile;
  final data = {
    'buttons': serializeButtons(buttons),
    'drawings': serializePaths(drawings),
  };
  return file.writeAsString(jsonEncode(data));
}

// 加载应用状态
Future<Map<String, dynamic>?> loadAppState() async {
  try {
    final file = await _stateFile;
    final contents = await file.readAsString();
    final json = jsonDecode(contents);
    return {
      'buttons': deserializeButtons(json['buttons']),
      'drawings': deserializePaths(json['drawings']),
    };
  } catch (e) {
    // 文件不存在或读取失败,返回null
    return null;
  }
}

方案二:使用Hive轻量数据库

Hive是NoSQL本地数据库,支持自定义对象存储,无需手动写大量序列化代码:

1. 配置依赖

在pubspec.yaml中添加:

dependencies:
  hive: ^2.2.3
  hive_flutter: ^1.1.0
dev_dependencies:
  hive_generator: ^1.1.5
  build_runner: ^2.4.6

2. 注册自定义类型适配器

为Offset生成适配器,让Hive能直接存储该类型:

// 初始化Hive
void initHive() async {
  await Hive.initFlutter();
  Hive.registerAdapter(OffsetAdapter());
  await Hive.openBox('app_state');
}

// Offset适配器实现
class OffsetAdapter extends TypeAdapter<Offset> {
  @override
  final typeId = 0;

  @override
  Offset read(BinaryReader reader) {
    return Offset(reader.readDouble(), reader.readDouble());
  }

  @override
  void write(BinaryWriter writer, Offset obj) {
    writer.writeDouble(obj.dx);
    writer.writeDouble(obj.dy);
  }
}

3. 保存与加载状态

// 保存状态到Hive
void saveStateToHive(List<Offset> buttons, List<Path> drawings) {
  final box = Hive.box('app_state');
  box.put('buttons', buttons);
  // Path可转成字节存储,还原时再转回Path
  box.put('drawings', drawings.map((p) => p.toBytes()).toList());
}

// 从Hive加载状态
Map<String, dynamic> loadStateFromHive() {
  final box = Hive.box('app_state');
  final buttons = box.get('buttons', defaultValue: <Offset>[]);
  final drawings = box.get('drawings', defaultValue: <List<int>>[])
      .map((bytes) => Path.fromBytes(bytes))
      .toList();
  return {'buttons': buttons, 'drawings': drawings};
}

关键注意事项

  • 如果绘图是像素位图,建议直接保存为图片文件,在状态中存储图片路径即可,避免序列化大体积数据。
  • 建议在应用退出时(如dispose方法、WillPopScope监听返回事件)触发状态保存,防止数据丢失。
  • 大体积绘图数据优先用文件存储,而非JSON或数据库,避免性能问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 23:23:14