首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >iOS长截图API

iOS长截图API

原创
作者头像
莫空9081
发布2022-04-20 21:36:24
1K0
发布2022-04-20 21:36:24
举报
文章被收录于专栏:iOS 备忘录iOS 备忘录

背景

Twitter 上看到TaioApp的作者说,iOS 系统有支持长截图的API——UIScreenshotService,从 iOS 13开始就可以使用,下午的时候就在自己的 APP 中体验了一下。

<!--more-->

过程

UIScreenshotService官方的说明如下:

When the user takes a screenshot of your app's content, you work with a UIScreenshotService object to provide a PDF version of that screenshot. You do not create a UIScreenshotService object directly. Instead, you retrieve the object from the screenshotService property of your window scene and assign a delegate to it. When the user takes a screenshot, UIKit asks your delegate for the PDF data.

截屏时,使用UIScreenshotService 最终提供的是 PDF,需要通过UIScreenshotServiceDelegate生成 PDF data.

使用如下:

把方法处理封装到单独的类,通过方法传入 view,来决定截屏时使用那个 view 来生成 PDF data。

.h文件

#import <Foundation/Foundation.h>

@interface WPSScreenShotHelper : NSObject

+ (instancetype)helper;

- (void)configScreenShotHelper:(UIScrollView *)scrollView;

@end

.m 文件

#import "MKScreenShotHelper.h"

@interface MKScreenShotHelper ()<UIScreenshotServiceDelegate>

@property (nonatomic, strong) UIScrollView *contentScrollView;

@end

@implementation MKScreenShotHelper

+ (instancetype)helper {
    static WPSScreenShotHelper *instance = nil;
    static dispatch_once_t onceToken;
    
    dispatch_once(&onceToken, ^{
        if (instance == nil) {
            instance = [WPSScreenShotHelper new];
        }
    });
    return instance;
}

- (instancetype)init {
    self = [super init];
    if (self) {
        if (@available(iOS 13.0, *)) {
            [UIApplication sharedApplication].keyWindow.windowScene.screenshotService.delegate = self;
        }
    }
    return self;
}

- (void)configScreenShotHelper:(UIScrollView *)scrollView {
    self.contentScrollView = scrollView;
}

#pragma mark - UIScreenshotServiceDelegate

- (void)screenshotService:(UIScreenshotService *)screenshotService generatePDFRepresentationWithCompletion:(void (^)(NSData * _Nullable, NSInteger, CGRect))completionHandler  API_AVAILABLE(ios(13.0)){
    
    // 临时改变 ScrollView 的 size,保证 ScrollView 能完全渲染
    CGRect frame = self.contentScrollView.frame;
    CGPoint contentOffset = self.contentScrollView.contentOffset;
    UIEdgeInsets contentInset = self.contentScrollView.contentInset;
    
    CGRect toFrame = frame;
    toFrame.size = self.contentScrollView.contentSize;
    self.contentScrollView.frame = toFrame;
    
    // 将 scrollView 渲染成 PDF
    NSMutableData *pdfData = [NSMutableData data];
    UIGraphicsBeginPDFContextToData(pdfData, self.contentScrollView.frame, nil);
    UIGraphicsBeginPDFPage();
    CGContextRef pdfContext = UIGraphicsGetCurrentContext();
    [self.contentScrollView.layer renderInContext:pdfContext];
    UIGraphicsEndPDFContext();
    
    // 恢复 scrollView 的 frame
    self.contentScrollView.frame = frame;
    self.contentScrollView.contentOffset = contentOffset;
    self.contentScrollView.contentInset = contentInset;
    
    // 回调结果
    completionHandler(pdfData, 0, CGRectZero);
}

@end

使用UIScreenshotService确实可以长截屏,截的内容的大小是ScrollView 的 contentSize。

但是有以下一些问题,需要注意:

  1. 不在 ScrollView 上的内容使用UIScreenshotService时看不到,比如 navigationBar、tabBar。
  2. webview 的截屏,通过获取 webview 的 scrollview 的高度,也可以截到。但是,如果是 webview 里面加载的网页中间或者网页部分使用了滑动,即不是 WebView 的 Scroll而是 H5网页里的 Scroll,这样的显示,UIScreenshotService是获取不到的,因为最后不管怎么获取 webview 的 scrollview 的 contentSize 的Height一直都是那么高,滑动的部分不是这个 scrollview。
  3. 使用了CAShapeLayer之类的,生成圆角或者其他,如果没有设置 layer 的 fillColor,最终UIScreenshotService显示出来会是纯黑的。
  4. 由于方法的回调依赖 scrollView 生成 PDF data,所以每个需要截图的界面,在进入时,都需要手动更新 contentScrollView,二级界面的还好说,可以hook scrollView 的初始化方法,保证每次创建时都更新 helper 的 contentScrollView,但是一级界面的几个 tab 切换,则只能通过手动更新的方式来设置(或者根据 tabIndex 获取不同的 scrollview),总之这也是需要注意的地方。

总结

UIScreenshotService确实能生成长截图,对于项目结构相对简洁明了、代码比较规范、只需要某个原生页面支持长截图的 APP 来说,可以使用。

但是如果项目中 H5多,且项目结构复杂的话,使用就不太方便了。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 背景
  • 过程
  • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档