flutter:截屏

作者: ChaosHeart | 来源:发表于2020-09-16 16:06 被阅读0次

    1.flutter-截屏组件

    import 'dart:typed_data';
    import 'dart:ui';
    
    import 'package:flutter/material.dart';
    import 'package:flutter/rendering.dart';
    
    class RepaintBoundaryPage extends StatefulWidget {
      @override
      _RepaintBoundaryPageState createState() => _RepaintBoundaryPageState();
    }
    
    class _RepaintBoundaryPageState extends State<RepaintBoundaryPage> {
      //全局key
      GlobalKey _rootWidgetKey = GlobalKey();
      //图片数组
      List<Uint8List> _images = List();
    
      ///截图
      Future<Uint8List> _capturePng(
        GlobalKey globalKey, {
        double pixelRatio = 1.0, //截屏的图片与原图的比例
      }) async {
        try {
          RenderRepaintBoundary boundary =
              globalKey.currentContext.findRenderObject();
          var image = await boundary.toImage(pixelRatio: pixelRatio);
          ByteData byteData = await image.toByteData(format: ImageByteFormat.png);
          Uint8List pngBytes = byteData.buffer.asUint8List();
          return pngBytes;
        } catch (e) {
          print(e);
        }
        return null;
      }
    
      ///build
      @override
      Widget build(BuildContext context) {
        //RepaintBoundary 截屏组件
        return RepaintBoundary(
          key: _rootWidgetKey,
          child: Scaffold(
            appBar: AppBar(
              title: Text("flutter组件截图"),
            ),
            body: Column(
              children: <Widget>[
                FlatButton(
                  onPressed: () {
                    //获取截屏图像
                    Future<Uint8List> pngBytes = _capturePng(_rootWidgetKey);
                    //添加到图片数组中
                    pngBytes.then((Uint8List value) {
                      _images.add(value);
                    });
                    setState(() {});
                  },
                  child: Text("全屏截图"),
                ),
                Expanded(
                  child: ListView.builder(
                    itemBuilder: (context, index) {
                      return Image.memory(
                        _images[index],
                        fit: BoxFit.cover,
                      );
                    },
                    itemCount: _images.length,
                    scrollDirection: Axis.horizontal,
                  ),
                )
              ],
            ),
          ),
        );
      }
    }
    
    

    2.flutter-截屏插件

    screenshot: ^0.2.0
    
    import 'dart:io';
    
    import 'package:flutter/material.dart';
    import 'package:screenshot/screenshot.dart';
    
    class FlutterScreenshotsPage extends StatefulWidget {
      @override
      _FlutterScreenshotsPageState createState() => _FlutterScreenshotsPageState();
    }
    
    class _FlutterScreenshotsPageState extends State<FlutterScreenshotsPage> {
      //截屏图片路径
      File _imageFile;
    
      //截屏控制器
      ScreenshotController screenshotController = ScreenshotController();
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text("flutter插件截屏"),
          ),
          body: Container(
            child: new Center(
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  //截屏组件
                  Screenshot(
                    controller: screenshotController,
                    child: Column(
                      children: <Widget>[
                        Text('截屏的位置'),
                        FlutterLogo(),
                      ],
                    ),
                  ),
                  _imageFile != null ? Image.file(_imageFile) : Container(),
                ],
              ),
            ),
          ),
          floatingActionButton: FloatingActionButton(
            onPressed: () {
              _imageFile = null;
              screenshotController
                  .capture(delay: Duration(milliseconds: 10))
                  .then((File image) async {
                setState(() {
                  _imageFile = image;
                });
                print("File Saved to Gallery");
              }).catchError((onError) {
                print(onError);
              });
            },
            tooltip: 'Increment',
            child: Icon(Icons.add),
          ),
        );
      }
    }
    
    

    3.flutter-iOS原生截屏

    import 'dart:typed_data';
    
    import 'package:flutter/material.dart';
    import 'package:flutter/services.dart';
    
    class IosScreenshotsPage extends StatefulWidget {
      @override
      _IosScreenshotsPageState createState() => _IosScreenshotsPageState();
    }
    
    class _IosScreenshotsPageState extends State<IosScreenshotsPage> {
      //平台信道
      MethodChannel _channel = MethodChannel("Screenshots");
    
      bool _image = false;
      Uint8List _image8List;
    
      //图片
      ///initState
      @override
      void initState() {
        //监听原生
        _channel.setMethodCallHandler((call) {
          //接收截屏后的图片
          if (call.method == "endScreenshots") {
            Map map = call.arguments;
            _image8List = map["image"];
            _image = true;
            print("接收原生的图片数据: $_image8List");
            setState(() {});
          }
          return null;
        });
        super.initState();
      }
    
      ///build
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text("iOS原生截屏"),
          ),
          body: Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: <Widget>[
                OutlineButton(
                  onPressed: () {
                    //发送开始截屏到原生
                    _channel.invokeMethod("startScreenshots");
                  },
                  child: Text("发起截屏"),
                ),
                Expanded(
                  child: _image
                      ? Image.memory(
                          _image8List,
                          fit: BoxFit.cover,
                        )
                      : Container(),
                ),
              ],
            ),
          ),
        );
      }
    }
    
    

    iOS代码

    //
    //  ScreenshotsManager.h
    //  Runner
    //
    //  Created by macmini on 2020/9/15.
    //
    
    #import <Foundation/Foundation.h>
    #import <UIKit/UIKit.h>
    
    NS_ASSUME_NONNULL_BEGIN
    
    /// 协议
    @protocol ScreenshotsManagerDelegate <NSObject>
    
    /// 图片保存结果
    - (void)isSaveImage:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo;
    
    @end
    
    
    /// 截屏类
    @interface ScreenshotsManager : NSObject
    
    /// 代理
    @property(nonatomic,assign)id<ScreenshotsManagerDelegate>delegate;
    
    /// 初始化
    + (instancetype)shareInstance;
    
    /// 返回系统级截屏PNG数据
    - (NSData *)screenshotsDataFromUIImagePNGRepresentation;
    /// 返回系统级截屏JPG数据
    - (NSData *)screenshotsDataFromUIImageJPEGRepresentation;
    /// 返回系统级截屏图片
    - (UIImage *)imageFromScreenshots;
    
    /// 保存图片到本地
    /// @param savedImage 需保存的图片
    - (void)saveImageToPhotos:(UIImage*)savedImage;
    
    @end
    
    NS_ASSUME_NONNULL_END
    
    
    //
    //  ScreenshotsManager.m
    //  Runner
    //
    //  Created by macmini on 2020/9/15.
    //
    
    #import "ScreenshotsManager.h"
    
    
    @implementation ScreenshotsManager
    
    ///强指针,应用结束才会死
    static id _instance;
    
    ///外调单例方法
    + (instancetype)shareInstance
    {
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            _instance = [[self alloc] init];
        });
        return _instance;
    }
    
    ///根本上只建立一个对象,只开辟一个内存
    + (instancetype)allocWithZone:(struct _NSZone *)zone {
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            _instance = [super allocWithZone:zone];
        });
        return _instance;
    }
    
    ///防止copy时,新建立一个对象,保证只开辟一个内存
    - (id)copyWithZone:(nullable NSZone *)zone
    {
        return _instance;
    }
    
    
    /************************************以上为单例****************************************/
    
    
    #pragma mark - 系统级截屏
    /// 返回系统级截屏PNG数据
    - (NSData *)screenshotsDataFromUIImagePNGRepresentation
    {
        UIImage *image = [self imageFromScreenshots];
        return UIImagePNGRepresentation(image);
    }
    
    /// 返回系统级截屏JPG数据
    - (NSData *)screenshotsDataFromUIImageJPEGRepresentation
    {
        UIImage *image = [self imageFromScreenshots];
        return UIImageJPEGRepresentation(image, 1.0f);
    }
    
    /// 返回系统级截屏图片
    - (UIImage *)imageFromScreenshots
    {
        CGSize imageSize = CGSizeZero;
        UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
        if (UIInterfaceOrientationIsPortrait(orientation))
        {
            imageSize = [UIScreen mainScreen].bounds.size;
        }
        else {
            imageSize = CGSizeMake([UIScreen mainScreen].bounds.size.height, [UIScreen mainScreen].bounds.size.width);
        }
        
        UIGraphicsBeginImageContextWithOptions(imageSize, NO, 0);
        CGContextRef context = UIGraphicsGetCurrentContext();
        for (UIWindow *window in [[UIApplication sharedApplication] windows])
        {
            CGContextSaveGState(context);
            CGContextTranslateCTM(context, window.center.x, window.center.y);
            CGContextConcatCTM(context, window.transform);
            CGContextTranslateCTM(context, -window.bounds.size.width * window.layer.anchorPoint.x, -window.bounds.size.height * window.layer.anchorPoint.y);
            if (orientation == UIInterfaceOrientationLandscapeLeft)
            {
                CGContextRotateCTM(context, M_PI_2);
                CGContextTranslateCTM(context, 0, -imageSize.width);
            }
            else if (orientation == UIInterfaceOrientationLandscapeRight)
            {
                CGContextRotateCTM(context, -M_PI_2);
                CGContextTranslateCTM(context, -imageSize.height, 0);
            }
            else if (orientation == UIInterfaceOrientationPortraitUpsideDown)
            {
                CGContextRotateCTM(context, M_PI);
                CGContextTranslateCTM(context, -imageSize.width, -imageSize.height);
            }
            if ([window respondsToSelector:@selector(drawViewHierarchyInRect:afterScreenUpdates:)]) {
                [window drawViewHierarchyInRect:window.bounds afterScreenUpdates:YES];
            }
            else {
                [window.layer renderInContext:context];
            }
            CGContextRestoreGState(context);
        }
        
        UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        return image;
    }
    
    #pragma mark - 将图片保存到相册
    //保存图片到本地
    - (void)saveImageToPhotos:(UIImage*)savedImage
    {
        UIImageWriteToSavedPhotosAlbum(savedImage, self, @selector(image:didFinishSavingWithError:contextInfo:), NULL);
    }
    // 指定回调方法
    - (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo
    {
        NSString *msg = nil;
        BOOL isSave;
        
        if(error != NULL) {
            msg = @"保存失败!" ;
            isSave = NO;
        }
        else {
            msg = @"保存成功!" ;
            isSave = YES;
        }
        ///代理回调
        [_delegate isSaveImage:image didFinishSavingWithError:error contextInfo:contextInfo];
    }
    
    @end
    
    

    4.获取UIView的截图

    //
    //  UIView+Screenshots.h
    //  Runner
    //
    //  Created by macmini on 2020/9/16.
    //
    
    #import <UIKit/UIKit.h>
    
    NS_ASSUME_NONNULL_BEGIN
    
    ///截图类
    @interface UIView (Screenshots)
    /**
     普通的截图
     该API仅可以在未使用layer和OpenGL渲染的视图上使用
    
     @return 截取的图片
     */
    - (UIImage *)nomalSnapshotImage;
    
    /**
     针对有用过OpenGL渲染过的视图截图
    
     @return 截取的图片
     */
    - (UIImage *)openglSnapshotImage;
    
    /**
     截图
     以UIView 的形式返回(_UIReplicantView)
    
     @return 截取出来的图片转换的视图
     */
    - (UIView *)snapshotView;
    
    @end
    
    NS_ASSUME_NONNULL_END
    
    
    //
    //  UIView+Screenshots.m
    //  Runner
    //
    //  Created by macmini on 2020/9/16.
    //
    
    #import "UIView+Screenshots.h"
    
    @implementation UIView (Screenshots)
    
    /**
     普通的截图
     该API仅可以在未使用layer和OpenGL渲染的视图上使用
    
     @return 截取的图片
     */
    - (UIImage *)nomalSnapshotImage
    {
        UIGraphicsBeginImageContextWithOptions(self.bounds.size, NO, [UIScreen mainScreen].scale);
        [self.layer renderInContext:UIGraphicsGetCurrentContext()];
        UIImage *snapshotImage = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
    
        return snapshotImage;
    }
    
    /**
     针对有用过OpenGL渲染过的视图截图
    
     @return 截取的图片
     */
    - (UIImage *)openglSnapshotImage
    {
        CGSize size = self.bounds.size;
        UIGraphicsBeginImageContextWithOptions(size, NO, [UIScreen mainScreen].scale);
        CGRect rect = self.frame;
        [self drawViewHierarchyInRect:rect afterScreenUpdates:YES];
        UIImage *snapshotImage = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
    
        return snapshotImage;
        
    }
    
    /**
     截图
     以UIView 的形式返回(_UIReplicantView)
    
     @return 截取出来的图片转换的视图
     */
    - (UIView *)snapshotView
    {
        UIView *snapView = [self snapshotViewAfterScreenUpdates:YES];
        return snapView;
    }
    
    
    @end
    
    

    5.获取UIWebView的截图

    //
    //  UIWebView+Screenshots.h
    //  Runner
    //
    //  Created by macmini on 2020/9/16.
    //
    
    #import <UIKit/UIKit.h>
    
    NS_ASSUME_NONNULL_BEGIN
    
    ///截图
    @interface UIWebView (Screenshots)
    
    ///UIWebView截图
    - (UIImage *)imageForWebView;
    
    @end
    
    NS_ASSUME_NONNULL_END
    
    
    //
    //  UIWebView+Screenshots.m
    //  Runner
    //
    //  Created by macmini on 2020/9/16.
    //
    
    #import "UIWebView+Screenshots.h"
    
    @implementation UIWebView (Screenshots)
    
    ///UIWebView截图
    - (UIImage *)imageForWebView
    {
        // 1.获取WebView的宽高
        CGSize boundsSize = self.bounds.size;
        CGFloat boundsWidth = boundsSize.width;
        CGFloat boundsHeight = boundsSize.height;
        
        // 2.获取contentSize
        CGSize contentSize = self.scrollView.contentSize;
        CGFloat contentHeight = contentSize.height;
        // 3.保存原始偏移量,便于截图后复位
        CGPoint offset = self.scrollView.contentOffset;
        // 4.设置最初的偏移量为(0,0);
        [self.scrollView setContentOffset:CGPointMake(0, 0)];
        
        NSMutableArray *images = [NSMutableArray array];
        while (contentHeight > 0) {
            // 5.获取CGContext 5.获取CGContext
            UIGraphicsBeginImageContextWithOptions(boundsSize, NO, 0.0);
            CGContextRef ctx = UIGraphicsGetCurrentContext();
            // 6.渲染要截取的区域
            [self.layer renderInContext:ctx];
            UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
            UIGraphicsEndImageContext();
            // 7.截取的图片保存起来
            [images addObject:image];
            
            CGFloat offsetY = self.scrollView.contentOffset.y;
            [self.scrollView setContentOffset:CGPointMake(0, offsetY + boundsHeight)];
            contentHeight -= boundsHeight;
        }
        // 8 webView 恢复到之前的显示区域
        [self.scrollView setContentOffset:offset];
        CGFloat scale = [UIScreen mainScreen].scale;
        CGSize imageSize = CGSizeMake(contentSize.width * scale,
                                      contentSize.height * scale);
        // 9.根据设备的分辨率重新绘制、拼接成完整清晰图片
        UIGraphicsBeginImageContext(imageSize);
        [images enumerateObjectsUsingBlock:^(UIImage *image, NSUInteger idx, BOOL *stop) {
            [image drawInRect:CGRectMake(0,scale * boundsHeight * idx,scale * boundsWidth,scale * boundsHeight)];
        }];
        UIImage *fullImage = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        
        return fullImage;
    }
    
    
    @end
    
    

    相关文章

      网友评论

        本文标题:flutter:截屏

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