继续更新Flutter系列,本篇记录如何在Flutter中进行截图,在Flutter中万物皆组件,不但高斯模糊是套一层组件,截图也是套一层组件,所以屏幕截图和组件截图其实是一个意思。虽然Flutter的这种嵌套UI很繁琐,但是用习惯了反而会感觉结构很清晰,不用担心布局相关代码的混乱,在FlutterInspector识图下更是一目了然,可以在不翻阅代码的情况下快速理解别人写的布局。
本次用到的组件是RepaintBoundary,效果图:
创建Flutter工程
依照惯例,创建一个简单的Flutter工程,清理main.dart中无用的代码便于演示:
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Column(),
);
}
}
这就是一个带有标题栏的空界面。
写一个简单的场景
便于演示,在这个界面中加入一个gif图片,当然你用普通图片或者视频也是可以的:
class _MyHomePageState extends State<MyHomePage> {
Future<Uint8List> _capturePng() async {
//TODO 进行截图
}
@override
Widget build(BuildContext context) {
return 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("全屏截图"),
),
],
),
);
}
}
加入图片之后我顺便加入了一个FlatButton组件,通过这个点击这个按钮来触发截图的逻辑。
当然到目前为止这还是只是一个简单的界面布局,没有用到任何新的东西。
如何截图
前面说到本篇会用到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,
),
)
],
),
),
);
}
}
完工。
更多干货移步我的个人博客 https://www.nightfarmer.top/