Flutter如何将Widget转PNG图片并保存到内部存储自定义创建的目录
Flutter 应用专属目录创建+Widget转PNG保存完整实现
1. 添加依赖
先在项目根目录的pubspec.yaml中添加如下依赖:
dependencies: flutter: sdk: flutter # 用于Widget转图片 screenshot: ^2.1.0 # 用于获取应用存储路径 path_provider: ^2.1.1 # 用于路径拼接处理 path: ^1.8.3 # 用于判断首次安装 shared_preferences: ^2.2.2
添加后执行flutter pub get安装依赖。
2. 核心实现代码
直接替换lib/main.dart内容即可,所有逻辑都加了注释可直接修改:
import 'dart:io'; import 'dart:typed_data'; import 'package:flutter/material.dart'; import 'package:screenshot/screenshot.dart'; import 'package:path_provider/path_provider.dart'; import 'package:shared_preferences/shared_preferences.dart'; // 全局存储专属目录路径 late String saveDirPath; void main() async { // 初始化Flutter绑定 WidgetsFlutterBinding.ensureInitialized(); // 初始化SharedPreferences final prefs = await SharedPreferences.getInstance(); // 获取应用内部文档目录(专属目录,无需申请存储权限) final appDocDir = await getApplicationDocumentsDirectory(); saveDirPath = '${appDocDir.path}/custom_screenshots'; // 判断是否首次安装 bool isFirstRun = prefs.getBool('first_run') ?? true; if (isFirstRun) { // 创建专属目录,recursive为true表示父目录不存在时一并创建 await Directory(saveDirPath).create(recursive: true); // 标记已非首次启动 await prefs.setBool('first_run', false); } runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( title: 'Widget转PNG demo', theme: ThemeData(primarySwatch: Colors.blue), home: const HomePage(), ); } } class HomePage extends StatefulWidget { const HomePage({super.key}); @override State<HomePage> createState() => _HomePageState(); } class _HomePageState extends State<HomePage> { // 实例化截图控制器 final ScreenshotController _screenshotController = ScreenshotController(); // 保存截图的方法 Future<void> saveWidgetToPng() async { try { // 截取目标Widget为Uint8List格式 Uint8List? imageBytes = await _screenshotController.capture(); if (imageBytes == null) { if(mounted) { ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('截图失败,请重试'))); } return; } // 生成保存路径,用时间戳作为文件名避免重复 String savePath = '$saveDirPath/${DateTime.now().millisecondsSinceEpoch}.png'; // 写入文件 await File(savePath).writeAsBytes(imageBytes); if(mounted) { ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('图片已保存至:$savePath'))); } } catch (e) { if(mounted) { ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('保存失败:$e'))); } } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Widget转PNG示例')), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ // 用Screenshot包裹需要转成PNG的目标Widget,可替换为任意自定义页面 Screenshot( controller: _screenshotController, child: Container( width: 300, height: 300, color: Colors.white, child: const Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(Icons.flutter_dash, size: 100, color: Colors.blue), Text( '我是要被转成PNG的内容', style: TextStyle(fontSize: 18, color: Colors.black), ) ], ), ), ), const SizedBox(height: 40), // 触发截图保存的按钮 ElevatedButton( onPressed: saveWidgetToPng, child: const Text('点击将上方Widget保存为PNG'), ) ], ), ), ); } }
3. 功能说明
- 首次安装逻辑:应用首次启动时会自动在应用内部专属文档目录下创建
custom_screenshots文件夹,该目录仅当前应用可访问,无需申请任何存储权限 - 可自定义截图范围:只需将需要转成PNG的Widget用
Screenshot组件包裹即可,支持普通Widget、列表、自定义页面等所有Flutter组件 - 保存逻辑:图片按时间戳命名,避免覆盖,保存成功后会弹出路径提示,可根据需求调整命名规则和存储路径
内容的提问来源于stack exchange,提问作者Mohammad Alamoudi
相关产品推荐
相关产品推荐

