chaoxiao 2020-04-15
https://www.jianshu.com/p/6801ecbee03d
/** * const RepaintBoundary({ Key key, Widget child }) */ //import ‘dart:io‘; //import ‘dart:typed_data‘; //import ‘package:flutter/material.dart‘; //import ‘package:flutter/rendering.dart‘; //import ‘dart:ui‘; //import ‘package:path_provider/path_provider.dart‘; class Widget_RepaintBoundary_State extends State<Widget_RepaintBoundary_Page> { GlobalKey globalKey = new GlobalKey(); Future<File> _capture() async { try { RenderRepaintBoundary boundary = globalKey.currentContext .findRenderObject(); //boundary.toImage()转化为ui.Image对象,不会自动为包裹的组件添加背景,不设置可能会缺失背景 var image = await boundary.toImage(pixelRatio: window.devicePixelRatio); //将image转化为byteData ByteData byteData = await image.toByteData(format: ImageByteFormat.png); //这个对象就是图片数据 Uint8List pngBytes = byteData.buffer.asUint8List(); String sTempDir = (await getTemporaryDirectory()).path; bool isDirExist = await Directory(sTempDir).exists(); if (!isDirExist) { Directory(sTempDir).create(); } Future<File> file = File(sTempDir + "/abc.png").writeAsBytes(pngBytes); return file; } catch (e) { print(e); } return null; } @override Widget build(BuildContext context) { var file = "/data/user/0/com.yourcompany.test1/cache/abc.png"; return MaterialApp( home: Scaffold( appBar: AppBar( title: Text("RepaintBoundary"), ), body: Column( children: <Widget>[ RepaintBoundary( key: globalKey, child: Text("RepaintBoundary组件"), ), RaisedButton( onPressed: () { _capture().then((_file){ setState(() { debugPrint(_file.path); file = _file.path; }); }).whenComplete((){ }); } ), Image.asset(file), ], ) ), ); } }
前面说到本篇会用到RepaintBoundary
组件,接下来把它套在你想要截图的组件的外层,想截全屏的话就套在最外面就可以,Flutter的这种写法习惯就好。
同时定义一个Key用来操作这个组件
class _MyHomePageState extends State<MyHomePage> { GlobalKey rootWidgetKey = GlobalKey(); ... @override Widget build(BuildContext context) { return RepaintBoundary( key: rootWidgetKey, child: Scaffold( appBar: AppBar( title: Text(widget.title), ), body: Column( ..... ), ), ); } }
通过rootWidgetKey可以拿到RenderRepaintBoundary的引用,进来拿到内部组件的截图:
class _MyHomePageState extends State<MyHomePage> { GlobalKey rootWidgetKey = GlobalKey(); Future<Uint8List> _capturePng() async { try { RenderRepaintBoundary boundary = rootWidgetKey.currentContext.findRenderObject(); var image = await boundary.toImage(pixelRatio: 3.0); ByteData byteData = await image.toByteData(format: ImageByteFormat.png); Uint8List pngBytes = byteData.buffer.asUint8List(); return pngBytes;//这个对象就是图片数据 } catch (e) { print(e); } return null; } ... }
通过上面一系列的方法调用,就拿到了一个Unit8List类型的图片数据。
而Unit8List类型的图片数据的显示也非常简单,通过Image.memory方法从内存中加载图片,下面附上完整的State代码:
class _MyHomePageState extends State<MyHomePage> { GlobalKey rootWidgetKey = GlobalKey(); List<Uint8List> images = List(); _capturePng() async { try { RenderRepaintBoundary boundary = rootWidgetKey.currentContext.findRenderObject(); var image = await boundary.toImage(pixelRatio: 3.0); ByteData byteData = await image.toByteData(format: ImageByteFormat.png); Uint8List pngBytes = byteData.buffer.asUint8List(); images.add(pngBytes); setState(() {}); return pngBytes; } catch (e) { print(e); } return null; } @override Widget build(BuildContext context) { return RepaintBoundary( key: rootWidgetKey, child: Scaffold( appBar: AppBar( title: Text(widget.title), ), body: Column( children: <Widget>[ Image.network( "http://qiniu.nightfarmer.top/test.gif", width: 300, height: 300, ), FlatButton( onPressed: () { this._capturePng(); }, child: Text("全屏截图"), ), Expanded( child: ListView.builder( itemBuilder: (context, index) { return Image.memory( images[index], fit: BoxFit.cover, ); }, itemCount: images.length, scrollDirection: Axis.horizontal, ), ) ], ), ), ); } }