美文网首页All in FlutterFlutter开发圈Flutter
Flutter之屏幕截图/组件截图

Flutter之屏幕截图/组件截图

作者: NightFarmer | 来源:发表于2018-12-18 12:04 被阅读21次

    继续更新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/

    相关文章

      网友评论

        本文标题:Flutter之屏幕截图/组件截图

        本文链接:https://www.haomeiwen.com/subject/bnwkkqtx.html