需求是:去中心化APP实现用户头像修改功能。
一共想到了三种方式:
1、将图片的path存在shared_preferences中
缺点:实际保存的是图片在设备中的地址,一旦用户将图片删除,该地址就无法读取出图片,那么头像就无法显示了
2、将图片转成base64编码字符串,存在shared_preferences中
实现代码:
import 'dart:convert';
import 'dart:io';
import 'package:shared_preferences/shared_preferences.dart';
1. 将图片转换为 Base64 编码的字符串
Future<String> encodeImageToBase64(File image) async {
final bytes = await image.readAsBytes();
return base64Encode(bytes);
}
2. 将 Base64 编码的字符串存储到 SharedPreferences 中
Future<void> saveImageToSharedPreferences(String key, File image) async {
// 将图片转换为 Base64 编码的字符串
final base64String = await encodeImageToBase64(image);
// 获取 SharedPreferences 实例
final prefs = await SharedPreferences.getInstance();
// 存储 Base64 编码字符串
await prefs.setString(key, base64String);
}
3. 从 SharedPreferences 中读取和解码图片
final prefs = await SharedPreferences.getInstance();
final storedBase64String = prefs.getString('image_base64');
if (storedBase64String != null) {
setState(() {
base64String = storedBase64String;
imageBytes = base64Decode(storedBase64String);
});
}
Widget build(BuildContext context) {
return Center(
child: imageBytes == null
? CircularProgressIndicator() // 显示加载指示器直到图片加载完成
: Image.memory(imageBytes!), // 使用 Image.memory 显示图片
);
}
缺点:base64字符串解码成图片的时间太长,UI切换时头像会闪烁,使用感差
3、将图片存在应用的沙盒目录中,再将图片路径存在shared_preferences中,一般用户不会访问更不会删除沙盒目录中的文件,所以相对来说是最优解。
实现代码:
import 'package:path/path.dart';
import 'package:path_provider/path_provider.dart';
File? avatar = null;
/**从设备中选取图片*/
final ImagePicker picker = ImagePicker();
final XFile? image = await picker.pickImage( source: ImageSource.camera);//相机拍照
if (image == null)
return; // 处理用户取消拍照的情况
setState(() {
avatar = File(image.path);
});
/**点击‘保存’按钮*/
TextButton(
onPressed: () async {
print("确认修改");
var _avatar = await saveImageToCustomDirectory(avatar);
if (_avatar == 'error') {
showToast('保存失败');
return;
}
//保存图片地址
SharedPreferences prefs = await SharedPreferences.getInstance();
await prefs.setString('avatar', !_avatar );
}
child:Text('保存修改');
)
//将图片存入沙盒目录,返回图片地址
Future<String> saveImageToCustomDirectory(File? image) async {
if (image == null) {
return '';
}
try {
deleteImageFromDirectory(Global.userNewWallet.avatar);
// 获取应用的沙盒目录
final directory = await getApplicationDocumentsDirectory();
// 自定义创建名为 'images' 的目录
final customDir = Directory('${directory.path}/images');
// 检查目录是否存在,存在就跳过创建
if (!customDir.existsSync()) {
await customDir.create(recursive: true);
}
// 保存图片到该目录
final imagePath = '${customDir.path}/${basename(image.path)}';
await image.copy(imagePath); // 使用 copy 方法将文件复制到目标位置
return imagePath; // 返回图片路径
} catch (e) {
print(e);
return 'error';
}
}
//将图片从沙盒目录删除
Future<void> deleteImageFromDirectory(String? imagePath) async {
if (imagePath == null) {
return;
}
final file = File(imagePath);
// 检查文件是否存在
if (await file.exists()) {
try {
await file.delete();
print('Image deleted successfully.');
} catch (e) {
print('Error deleting image: $e');
}
} else {
print('Image file does not exist.');
}
}