同时按下 Home 键和电源键,咔嚓一声,就得到了一张手机的截图,这操作想必 iPhone 用户再熟悉不过了。我们作为研发人员,面对的是一个个的 View,那么该怎么用代码对 View 进行截图呢?
这篇文章主要讨论的是如何在包括 UIWebView 和 WKWebView 的网页中进行长截图。

UIWebView 截图

对 UIWebView 截图比较简单,renderInContext 这个方法相信大家都不会陌生,这个方法是 CALayer 的一个实例方法,可以用来对大部分 View 进行截图。我们知道,UIWebView 承载内容的其实是作为其子 View 的 UIScrollView,所以对 UIWebView 截图应该对其 scrollView 进行截图。具体的截图方法如下:

- (void)snapshotForScrollView:(UIScrollView *)scrollView
{// 1. 记录当前 scrollView 的偏移和位置CGPoint currentOffset = scrollView.contentOffset;CGRect currentFrame = scrollView.frame;scrollView.contentOffset = CGPointZero;// 2. 将 scrollView 展开为其实际内容的大小scrollView.frame = CGRectMake(0, 0, scrollView.contentSize.width, scrollView.contentSize.height);// 3. 第三个参数设置为 0 表示设置为屏幕的默认缩放因子UIGraphicsBeginImageContextWithOptions(scrollView.contentSize, YES, 0);[scrollView.layer renderInContext:UIGraphicsGetCurrentContext()];UIImage *snapshotImage = UIGraphicsGetImageFromCurrentImageContext();UIGraphicsEndImageContext();// 4. 重新设置 scrollView 的偏移和位置,还原现场scrollView.contentOffset = currentOffset;scrollView.frame = currentFrame;
}

WKWebView 截图

虽然 WKWebView 里也有 scrollView,但是直接对这个 scrollView 截图得到的是一片空白的,具体原因不明。一番 Google 之后可以看到好些人提到 drawViewHierarchyInRect 方法, 可以看到这个方法是 iOS 7.0 开始引入的。官方文档中描述为:

Renders a snapshot of the complete view hierarchy as visible onscreen into the current context.

注意其中的 visible onscreen,也就是将屏幕中可见部分渲染到上下文中,这也解释了为什么对 WKWebView 中的 scrollView 展开为实际内容大小,再调用 drawViewHierarchyInRect 方法总是得到一张不完整的截图(只有屏幕可见区域被正确截到,其他区域为空白)。
不过,这样倒是给我们提供了一个思路,可以将 WKWebView 按屏幕高度裁成 n 页,然后将 WKWebView 一页一页的往上推,每推一页就调用一次 drawViewHierarchyInRect 将当前屏幕的截图渲染到上下文中,最后调用 UIGraphicsGetImageFromCurrentImageContext 从上下文中获取的图片即为完整截图。

在这里我还是要推荐下我自己建的iOS开发学习群:680565220,群里都是学ios开发的,如果你正在学习ios ,小编欢迎你加入,今天分享的这个案例已经上传到群文件,大家都是软件开发党,不定期分享干货(只有iOS软件开发相关的),包括我自己整理的一份2018最新的iOS进阶资料和高级开发教程

核心代码如下(代码为演示用途,完整代码请从这里查看):

- (void)snapshotForWKWebView:(WKWebView *)webView
{// 1UIView *snapshotView = [webView snapshotViewAfterScreenUpdates:YES];[webView.superview addSubview:snapshotView];// 2CGPoint currentOffset = webView.scrollView.contentOffset;...// 3UIView *containerView = [[UIView alloc] initWithFrame:webView.bounds];[webView removeFromSuperview];[containerView addSubview:webView];// 4CGSize totalSize = webView.scrollView.contentSize;NSInteger page = ceil(totalSize.height / containerView.bounds.size.height);webView.scrollView.contentOffset = CGPointZero;webView.frame = CGRectMake(0, 0, containerView.bounds.size.width, webView.scrollView.contentSize.height);UIGraphicsBeginImageContextWithOptions(totalSize, YES, UIScreen.mainScreen.scale);[self drawContentPage:0 maxIndex:page completion:^{UIImage *snapshotImage = UIGraphicsGetImageFromCurrentImageContext();UIGraphicsEndImageContext();// 8[webView removeFromSuperview];...}];
}- (void)drawContentPage(NSInteger)index maxIndex:(NSInteger)maxIndex completion:(dispatch_block_t)completion
{// 5CGRect splitFrame = CGRectMake(0, index * CGRectGetHeight(containerView.bounds), containerView.bounds.size.width, containerView.frame.size.height);CGRect myFrame = webView.frame;myFrame.origin.y = -(index * containerView.frame.size.height);webView.frame = myFrame;// 6[targetView drawViewHierarchyInRect:splitFrame afterScreenUpdates:YES];// 7if (index < maxIndex) {[self drawContentPage:index + 1 maxIndex:maxIndex completion:completion];} else {completion();}
}

代码注意项如下(对应代码注释中的序号):

  1. 为了截图时对 frame 进行操作不会出现闪屏等现象,我们需要盖一个“假”的 webView 到现在的位置上,并将真正的 webView “摘下来”。调用 snapshotViewAfterScreenUpdates 即可得到这样一个“假”的 webView
  2. 保存真正的 webView 的偏移、位置等信息,以便截图完成之后“还原现场”
  3. 用一个新的视图承载“真正的” webView,这个视图也是绘图所用到的上下文
  4. 将 webView 按照实际内容高度和屏幕高度分成 page 页
  5. 得到每一页的实际位置,并将 webView 往上推到该位置
  6. 调用 drawViewHierarchyInRect 将当前位置的 webView 渲染到上下文中
  7. 如果还未到达最后一页,则递归调用 drawViewHierarchyInRect 方法进行渲染;如果已经渲染完了全部页,则回调通知截图完成
  8. 调用 UIGraphicsGetImageFromCurrentImageContext 方法从当前上下文中获取到完整截图,将第 2 步中保存的信息重新赋予到 webView 上,“还原现场”

注意:我们的截图方法中有对 webView 的 frame 进行操作,如果其他地方如果有对 frame 进行操作的话,是会影响我们截图的。所以在截图时应该禁用掉其他地方对 frame 的改变,就像这样:

- (void)layoutWebView
{if (!_isCapturing) {self.wkWebView.frame = [self frameForWebView];}
}

结语

当前 WKWebView 的使用越来越广泛了,我随意查看了内存占用:打开同样一个网页,UIWebView 直接占用了 160 MB 内存,而 WKWebView 只占用了 40 MB 内存,差距是相当明显的。如果我们的业务中用到了 WKWebView 且有截图需求的话,那么还是得老老实实完成的。

更多编程分享请关注微信公众号:程序员大牛!

转载于:https://my.oschina.net/u/3778058/blog/1835529

iOS 截图的那些事儿相关推荐

  1. iOS分辨率的那些事儿

    1 iOS设备的分辨率 iOS设备,目前最主要的有3种(Apple TV等不在此讨论),按分辨率分为两类 iPhone/iPod Touch 普屏分辨率    320像素 x 480像素 Retina ...

  2. Unity iOS截图并保存到手机相册总结

    Unity iOS捕捉相机拍到的画面并截图保存到手机相册总结 本文专门针对小白,详细(图文)的写了通过unity 3d实现ios捕捉相机拍到的画面并截图保存到手机相册的方法.(对大佬来说可能写的略显繁 ...

  3. iOS签名校验那些事儿

    导读:iOS签名校验机制是苹果生态安全的基础,日常工作中无论是开发阶段还是测试阶段常常会遇到很多需要通过签名机制解决的问题,了解iOS签名机制的原理有助于提高我们解决相关问题的成本和效率.本文首先介绍 ...

  4. iOS 越狱开发那些事儿之二

    iOS越狱篇之二:iOSOpenDev环境搭建 主要参考网站:http://iosopendev.com/ 参考地址:http://blog.csdn.net/tuluigi/article/deta ...

  5. iOS 截图 截取屏幕

    // 从view上截图 - (UIImage *)getImage {UIGraphicsBeginImageContextWithOptions(CGSizeMake(150, 150), NO, ...

  6. iOS打包发布那些事儿

    摘要:一个iOS应用最终能在用户的设备上使用,是经过了开发 -> 打包 -> 发布 -> 下载安装过程的.为了更易于理解,以及避免从一开始就陷入细节,本文将逆序讲述整个过程. 一.背 ...

  7. iOS 截图 对view指定区域 以及 对图片 指定区域截图

    //MARK:获取截图,对view 制定区域截图static func getCropImage(_ view:UIView,size:CGSize) -> UIImage {//false是透 ...

  8. linux 构建ios_为iOS构建本机编辑器

    linux 构建ios 序幕 (Prologue) I have always been fascinated with the great Open Source community that al ...

  9. ios 容器类_在新的ios项目中使用的10个容器

    ios 容器类 If you start developing a new iOS app, you probably need to use several external libraries. ...

最新文章

  1. 华三h3c交换机最详细的配置实例手册_华为/思科/华三基本命令对比
  2. Postfix+Amavisd-new+Spamassassin+ClamAV整合安装
  3. 注意scrapy中SgmlLinkExtractor的默认deny_extensions
  4. oracle standby同步,ORACLE 利用rman增量备份同步standby库
  5. 电子书下载 | 超实用!阿里售后专家的 K8s 问题排查案例合集
  6. 2020年联通软件研究院校招笔试第三题
  7. 【ARM】Tiny4412裸板编程之MMU(段1M)
  8. IOS模拟器调试ANE
  9. linux默认的https端口,如何在Ubuntu 18.04 Bionic Beaver Linux上拒绝除HTTP端口80和HTTPS端口443之外的所有传入端口...
  10. 【AI视野·今日Robot 机器人论文速览 第十五期】Fri, 25 Jun 2021
  11. 嵌入式操作系统内核原理和开发(多线程轮转)
  12. android启动过程之init.rc文件浅析
  13. HTML基础整理(From表单)
  14. 虚拟麦克风音频输入_硅麦克风电路连接指南
  15. JAVA学习homework的Car、Bus、motoVehicle
  16. 开始自学PHP之路3(HTML)
  17. HmailServer部署应用(完整过程,含故障处理)
  18. C#中操作Word(8)—— 向Word中插入图表的三种方法(一)
  19. 抖音小程序实践二:常用权限申请
  20. 解决方案:h5网页外部浏览器唤起微信分享,唤起微信面板,分享朋友圈方案,兼容大部分浏览器

热门文章

  1. java list转数组
  2. 安卓linux免root权限,手机免root安装Linux发行版 Termux v0.106+Tmoe-linux
  3. android路由器app,微信小程序趋势及前景,复习指南
  4. 29岁年轻人离奇死亡:不是生活太苦,是你容易想得太多
  5. android1comgamemod,我的世界巫师之路mod手机版
  6. 全屏Dialog在小米手机上状态栏遮挡导致无法全屏。
  7. Notes(v070802)R6本地邮箱模版设置
  8. C++ 封装(2): 构造函数和析构函数
  9. AndroidTV 模拟器的搭建
  10. canvas绘制标尺