flutter:截屏

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();
  //圖片數(shù)組
  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);
                //添加到圖片數(shù)組中
                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> {
  //平臺(tái)信道
  MethodChannel _channel = MethodChannel("Screenshots");

  bool _image = false;
  Uint8List _image8List;

  //圖片
  ///initState
  @override
  void initState() {
    //監(jiān)聽原生
    _channel.setMethodCallHandler((call) {
      //接收截屏后的圖片
      if (call.method == "endScreenshots") {
        Map map = call.arguments;
        _image8List = map["image"];
        _image = true;
        print("接收原生的圖片數(shù)據(jù): $_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: () {
                //發(fā)送開始截屏到原生
                _channel.invokeMethod("startScreenshots");
              },
              child: Text("發(fā)起截屏"),
            ),
            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

/// 協(xié)議
@protocol ScreenshotsManagerDelegate <NSObject>

/// 圖片保存結(jié)果
- (void)isSaveImage:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo;

@end


/// 截屏類
@interface ScreenshotsManager : NSObject

/// 代理
@property(nonatomic,assign)id<ScreenshotsManagerDelegate>delegate;

/// 初始化
+ (instancetype)shareInstance;

/// 返回系統(tǒng)級(jí)截屏PNG數(shù)據(jù)
- (NSData *)screenshotsDataFromUIImagePNGRepresentation;
/// 返回系統(tǒng)級(jí)截屏JPG數(shù)據(jù)
- (NSData *)screenshotsDataFromUIImageJPEGRepresentation;
/// 返回系統(tǒng)級(jí)截屏圖片
- (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

///強(qiáng)指針,應(yīng)用結(jié)束才會(huì)死
static id _instance;

///外調(diào)單例方法
+ (instancetype)shareInstance
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _instance = [[self alloc] init];
    });
    return _instance;
}

///根本上只建立一個(gè)對(duì)象,只開辟一個(gè)內(nèi)存
+ (instancetype)allocWithZone:(struct _NSZone *)zone {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _instance = [super allocWithZone:zone];
    });
    return _instance;
}

///防止copy時(shí),新建立一個(gè)對(duì)象,保證只開辟一個(gè)內(nèi)存
- (id)copyWithZone:(nullable NSZone *)zone
{
    return _instance;
}


/************************************以上為單例****************************************/


#pragma mark - 系統(tǒng)級(jí)截屏
/// 返回系統(tǒng)級(jí)截屏PNG數(shù)據(jù)
- (NSData *)screenshotsDataFromUIImagePNGRepresentation
{
    UIImage *image = [self imageFromScreenshots];
    return UIImagePNGRepresentation(image);
}

/// 返回系統(tǒng)級(jí)截屏JPG數(shù)據(jù)
- (NSData *)screenshotsDataFromUIImageJPEGRepresentation
{
    UIImage *image = [self imageFromScreenshots];
    return UIImageJPEGRepresentation(image, 1.0f);
}

/// 返回系統(tǒng)級(jí)截屏圖片
- (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 - 將圖片保存到相冊(cè)
//保存圖片到本地
- (void)saveImageToPhotos:(UIImage*)savedImage
{
    UIImageWriteToSavedPhotosAlbum(savedImage, self, @selector(image:didFinishSavingWithError:contextInfo:), NULL);
}
// 指定回調(diào)方法
- (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;
    }
    ///代理回調(diào)
    [_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;

/**
 針對(duì)有用過OpenGL渲染過的視圖截圖

 @return 截取的圖片
 */
- (UIImage *)openglSnapshotImage;

/**
 截圖
 以UIView 的形式返回(_UIReplicantView)

 @return 截取出來的圖片轉(zhuǎn)換的視圖
 */
- (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;
}

/**
 針對(duì)有用過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 截取出來的圖片轉(zhuǎn)換的視圖
 */
- (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.保存原始偏移量案训,便于截圖后復(fù)位
    CGPoint offset = self.scrollView.contentOffset;
    // 4.設(shè)置最初的偏移量為(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.渲染要截取的區(qū)域
        [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 恢復(fù)到之前的顯示區(qū)域
    [self.scrollView setContentOffset:offset];
    CGFloat scale = [UIScreen mainScreen].scale;
    CGSize imageSize = CGSizeMake(contentSize.width * scale,
                                  contentSize.height * scale);
    // 9.根據(jù)設(shè)備的分辨率重新繪制、拼接成完整清晰圖片
    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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖棕兼,帶你破解...
    沈念sama閱讀 218,036評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異抵乓,居然都是意外死亡伴挚,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門灾炭,熙熙樓的掌柜王于貴愁眉苦臉地迎上來茎芋,“玉大人,你說我怎么就攤上這事蜈出“芑玻” “怎么了?”我有些...
    開封第一講書人閱讀 164,411評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵掏缎,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我煤杀,道長(zhǎng)眷蜈,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,622評(píng)論 1 293
  • 正文 為了忘掉前任沈自,我火速辦了婚禮酌儒,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘枯途。我一直安慰自己忌怎,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,661評(píng)論 6 392
  • 文/花漫 我一把揭開白布酪夷。 她就那樣靜靜地躺著榴啸,像睡著了一般。 火紅的嫁衣襯著肌膚如雪晚岭。 梳的紋絲不亂的頭發(fā)上鸥印,一...
    開封第一講書人閱讀 51,521評(píng)論 1 304
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼库说。 笑死狂鞋,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的潜的。 我是一名探鬼主播骚揍,決...
    沈念sama閱讀 40,288評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼啰挪!你這毒婦竟也來了信不?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,200評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤脐供,失蹤者是張志新(化名)和其女友劉穎浑塞,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體政己,經(jīng)...
    沈念sama閱讀 45,644評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡酌壕,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,837評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了歇由。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片卵牍。...
    茶點(diǎn)故事閱讀 39,953評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖沦泌,靈堂內(nèi)的尸體忽然破棺而出糊昙,到底是詐尸還是另有隱情,我是刑警寧澤谢谦,帶...
    沈念sama閱讀 35,673評(píng)論 5 346
  • 正文 年R本政府宣布释牺,位于F島的核電站,受9級(jí)特大地震影響回挽,放射性物質(zhì)發(fā)生泄漏没咙。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,281評(píng)論 3 329
  • 文/蒙蒙 一千劈、第九天 我趴在偏房一處隱蔽的房頂上張望祭刚。 院中可真熱鬧,春花似錦墙牌、人聲如沸涡驮。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,889評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)捉捅。三九已至,卻和暖如春鸿市,著一層夾襖步出監(jiān)牢的瞬間锯梁,已是汗流浹背即碗。 一陣腳步聲響...
    開封第一講書人閱讀 33,011評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留陌凳,地道東北人剥懒。 一個(gè)月前我還...
    沈念sama閱讀 48,119評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像合敦,于是被迫代替她去往敵國(guó)和親初橘。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,901評(píng)論 2 355