??????小菜因特別需求想嘗試一下 Flutter 頁面截屏并將圖片保存在本地的功能阅爽,記錄一下嘗試過程悦屏。
RepaintBoundary
??????Flutter 提供了支持截屏的 RepaintBoundary寞射,在需要截取部分的外層嵌套,也可以截取某一子 Widget 內容玻孟;RepaintBoundary 的結構很簡單缔杉,通過 key 來判斷截取的 RenderObject,最終生成一個 RenderRepaintBoundary 對象捏检;
const RepaintBoundary({ Key key, Widget child }) : super(key: key, child: child);
@override
Widget build(BuildContext context) {
return RepaintBoundary(
key: globalKey,
child: Scaffold(
body: Stack(children: <Widget>[
Image.asset('img/bg.jpg', width: _w, fit: BoxFit.fill),
Container(child: CustomPaint(painter: StarCanvas(_w, _h, p, s, st))),
itemWid(1, 2),
itemWid(1, 1),
itemWid(0, 1),
itemWid(0, 2),
])));
}
ui.Image
??????通過 RenderRepaintBoundary 獲取的對象 .toImage() 后轉為 ui.Image 類型字節(jié)流荞驴,最終存儲為 png 格式,在轉為常用的 Uint8List 存儲在內存中贯城,借助 image.memory() 方式展示在具體位置熊楼;而當前只是獲取到圖片的流信息,僅可用于操作能犯,還未存儲在本地鲫骗;
??????toByteData() 生成的數據格式一般分三種:
- rawRgba:未解碼的 byte;
- rawUnmodified:未解碼且未修改的 byte踩晶,如灰度圖执泰;
- png 為我們常用的 PNG 圖片;
Future<Uint8List> _capturePng(globalKey) async {
RenderRepaintBoundary boundary = globalKey.currentContext.findRenderObject();
ui.Image image = await boundary.toImage();
ByteData byteData = await image.toByteData(format: ui.ImageByteFormat.png);
Uint8List picBytes = byteData.buffer.asUint8List();
return picBytes;
}
Directory
??????若需要存儲本地渡蜻,跟 Android/iOS 類似术吝,首先獲取存儲路徑计济,再進行存儲操作;小菜借助三方插件 path_provider 來獲取圖片路徑排苍;
??????path_provider 提供了 getTemporaryDirectory 臨時路徑 / getApplicationDocumentsDirectory 全局路徑等沦寂,可以根據不同的需求存儲不同路徑;
??????小菜為了測試方便選擇存放在設備根目錄下 getExternalStorageDirectory淘衙;
Future<String> _capturePath(name) async {
Directory documentsDirectory = await getExternalStorageDirectory();
String path = join(documentsDirectory.path, name);
return path;
}
writeAsBytes
??????文件的保存很簡單传藏,直接將 Uint8List 寫入到所在文件路徑下即可;
File(val).writeAsBytes(unitVal);
??????但此時存儲或自定義文件路徑彤守,可能會遇到權限問題毯侦,小菜為了測試方便在 Android 中添加讀寫權限,并手動在設備中打開具垫,之后便可正常存儲侈离;
??????小菜對文件存儲還很不熟悉,對于動態(tài)申請權限方面也在學習過程中筝蚕,會在今后的博客中逐漸整理霍狰,如有不對的地方請多多指導!
來源:阿策小和尚