【问题标题】:How to take a screenshot of the current widget - Flutter如何截取当前小部件的屏幕截图 - Flutter
【发布时间】:2018-12-09 14:33:14
【问题描述】:

我需要截取当前屏幕或小部件的屏幕截图,并将其写入文件。

【问题讨论】:

    标签: flutter dart screenshot


    【解决方案1】:

    我试过了,找到了解决办法,

    import 'package:flutter/material.dart';
    import 'dart:async';
    import 'dart:typed_data';
    import 'dart:ui' as ui;
    import 'package:flutter/material.dart';
    import 'package:flutter/rendering.dart';
    import 'package:flutter/services.dart';
    import 'package:path_provider/path_provider.dart';
    import 'dart:io';
    
    void main() => runApp(new MyApp());
    
    class MyApp extends StatelessWidget {
      // This widget is the root of your application.
      @override
      Widget build(BuildContext context) {
        return new MaterialApp(
          title: 'Flutter Demo',
          theme: new ThemeData(
            primarySwatch: Colors.blue,
          ),
          home: new MyHomePage(title: 'Flutter Demo Home Page'),
        );
      }
    }
    
    class MyHomePage extends StatefulWidget {
      MyHomePage({Key key, this.title}) : super(key: key);
      final String title;
    
      @override
      _MyHomePageState createState() => new _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage> {
      static GlobalKey previewContainer = new GlobalKey();
      int _counter = 0;
    
      void _incrementCounter() {
        setState(() {
          // This call to setState tells the Flutter framework that something has
          // changed in this State, which causes it to rerun the build method below
          // so that the display can reflect the updated values. If we changed
          // _counter without calling setState(), then the build method would not be
          // called again, and so nothing would appear to happen.
          _counter++;
        });
      }
    
      @override
      Widget build(BuildContext context) {
    
        return RepaintBoundary(
            key: previewContainer,
          child: new Scaffold(
          appBar: new AppBar(
    
            title: new Text(widget.title),
          ),
          body: new Center(
            child: new Column(
    
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                new Text(
                  'You have pushed the button this many times:',
                ),
                new Text(
                  '$_counter',
                  style: Theme.of(context).textTheme.display1,
                ),
                new RaisedButton(
                    onPressed: takeScreenShot,
                  child: const Text('Take a Screenshot'),
                ),
              ],
            ),
          ),
          floatingActionButton: new FloatingActionButton(
            onPressed: _incrementCounter,
            tooltip: 'Increment',
            child: new Icon(Icons.add),
          ), // This trailing comma makes auto-formatting nicer for build methods.
        )
        );
      }
      takeScreenShot() async{
        RenderRepaintBoundary boundary = previewContainer.currentContext.findRenderObject();
        ui.Image image = await boundary.toImage();
        final directory = (await getApplicationDocumentsDirectory()).path;
        ByteData byteData = await image.toByteData(format: ui.ImageByteFormat.png);
        Uint8List pngBytes = byteData.buffer.asUint8List();
        print(pngBytes);
        File imgFile =new File('$directory/screenshot.png');
        imgFile.writeAsBytes(pngBytes);
      }
    }
    

    最后检查你的应用程序目录你会发现 screenshot.png !!

    【讨论】:

    • 我正在使用这段代码,但没有全屏截图
    • @mr.hir 我也是。我已经检查了这个github.com/flutter/flutter/issues/17687,但错误仍然存​​在。
    • 图像质量很差。有没有办法控制截图的质量?
    • 增加像素比应该会提高输出图像的质量。 ui.Image image = await boundary.toImage(pixelRatio: 2.0);
    • 他们有什么方法可以通过相同的方法或任何其他方法在 Flutter Web 应用程序中截取屏幕截图吗?我试过了,但没有用。
    【解决方案2】:

    假设您要截取FlutterLogo 小部件的屏幕截图。将其包装在 RepaintBoundary 中,将为它的 child 创建一个单独的显示列表。并提供钥匙

    var scr= new GlobalKey();
    RepaintBoundary(
             key: scr,
             child: new FlutterLogo(size: 50.0,))
    

    然后你可以通过将边界转换为图像来获得pngBytes

    takescrshot() async {
      RenderRepaintBoundary boundary = scr.currentContext.findRenderObject();
      var image = await boundary.toImage();
      var byteData = await image.toByteData(format: ImageByteFormat.png);
      var pngBytes = byteData.buffer.asUint8List();
      print(pngBytes);
      }
    

    【讨论】:

    • 我有一个问题 => 我的小部件 Listview 有 10 多个项目,因此屏幕无法显示所有项目,捕获的图像仅显示我们在屏幕上的内容。即使项目没有显示在屏幕上,是否有任何方法可以捕获整个 ListView?
    • @GPH 我不认为这是可能的,只是因为这些项目甚至还没有建成,所以没有人知道它们会是什么样子。
    • @MarcinSzałek ,您对此完全确定吗?重要的是我要发布一个关于它的问题:stackoverflow.com/questions/57583965/…
    • 我们如何创建jpg图像? png 图像是透明的并与背景混合。请分享任何建议。
    【解决方案3】:

    您可以使用screenshot插件来截取小部件。

    屏幕截图是一个简单的插件,可以将小部件捕获为图像。这个插件将你的小部件包装在RenderRepaintBoundary

    将此包用作库

    1. 将此添加到您的包的pubspec.yaml 文件中:

      dependencies:
        screenshot: ^0.2.0
      
    2. 现在在你的 Dart 代码中,导入它:

      import 'package:screenshot/screenshot.dart';
      

    这个方便的插件可用于捕获任何小部件,包括全屏屏幕截图和单个小部件,如 Text()

    1. 创建截图控制器实例

      class _MyHomePageState extends State<MyHomePage> {
        int _counter = 0;
        File _imageFile;
      
        //Create an instance of ScreenshotController
        ScreenshotController screenshotController = ScreenshotController(); 
      
        @override
        void initState() {
          // TODO: implement initState
          super.initState();
        }
      ...
      }
      
    2. 将要捕获的小部件包装在屏幕截图小部件中。将控制器分配给您之前创建的 screenshotController

      Screenshot(
        controller: screenshotController,
        child: Text("This text will be captured as image"),
      ),
      
    3. 调用 capture 方法截取屏幕截图。这将返回一个文件

      screenshotController.capture().then((File image) {
       //Capture Done
       setState(() {
           _imageFile = image;
       });
      }).catchError((onError) {
       print(onError);
      });
      

    【讨论】:

    • 对屏幕截图的重大更改 (0.3.0 10/02/2021)。捕获方法现在返回 Uint8List 而不是 File。
    【解决方案4】:

    运行

    flutter screenshot
    

    它将从您连接的设备中截取屏幕截图并将其保存到您正在进行开发的文件夹中,它会将flutter_01.jpg保存在您的文件夹中

    【讨论】:

    • 这会截取我的整个屏幕而不是模拟器。
    • 这不会捕获小部件。它只截取设备屏幕的屏幕截图。
    • 它给了我错误:Screenshot not supported for Linux.
    【解决方案5】:

    这里是flutter 2.0+方法截图并在社交媒体上分享的解决方案

     import 'package:flutter/rendering.dart';
            import 'package:flutter/services.dart';
            import 'dart:ui' as ui;
            import 'package:path_provider/path_provider.dart';
            import 'package:share/share.dart';
            
            GlobalKey previewContainer = new GlobalKey();
        
         @override
          Widget build(BuildContext context) {
            return Scaffold(
              appBar: AppBar(
                // Here we take the value from the MyHomePage object that was created by
                // the App.build method, and use it to set our appbar title.
                title: Text(widget.title),
              ),
              body: RepaintBoundary(
                key: previewContainer,
                child: Center(
                  // Center is a layout widget. It takes a single child and positions it
                  // in the middle of the parent.
                  child: Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: <Widget>[
                      Text(
                        'Take Screen Shot',
                      ),
                    ],
                  ),
                ),
              ),
              floatingActionButton: FloatingActionButton(
                onPressed: _captureSocialPng,
                tooltip: 'Increment',
                child: Icon(Icons.camera),
              ), // This trailing comma makes auto-formatting nicer for build methods.
            );
          }
        
            
              Future<void> _captureSocialPng() {
                List<String> imagePaths = [];
                final RenderBox box = context.findRenderObject() as RenderBox;
                return new Future.delayed(const Duration(milliseconds: 20), () async {
                  RenderRepaintBoundary? boundary = previewContainer.currentContext!
                      .findRenderObject() as RenderRepaintBoundary?;
                  ui.Image image = await boundary!.toImage();
                  final directory = (await getApplicationDocumentsDirectory()).path;
                  ByteData? byteData =
                      await image.toByteData(format: ui.ImageByteFormat.png);
                  Uint8List pngBytes = byteData!.buffer.asUint8List();
                  File imgFile = new File('$directory/screenshot.png');
                  imagePaths.add(imgFile.path);
                  imgFile.writeAsBytes(pngBytes).then((value) async {
                    await Share.shareFiles(imagePaths,
                        subject: 'Share',
                        text: 'Check this Out!',
                        sharePositionOrigin: box.localToGlobal(Offset.zero) & box.size);
                  }).catchError((onError) {
                    print(onError);
                  });
                });
              }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-05-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多