iOS-长截图 (学习记录)

这篇具有很好参考价值的文章主要介绍了iOS-长截图 (学习记录)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

长截图 —— 也就是可以截到超出屏幕的长图。在实现长图之前,我们先要了解一下iOS的绘制普通截图操作。在此基础上,来实现长截图。

iOS — 绘制截图

 UIGraphicsBeginImageContextWithOptions(CGSize size, BOOL opaque, CGFloat scale);
 [self.view.layer renderInContext:UIGraphicsGetCurrentContext()];
 UIImage *img = UIGraphicsGetImageFromCurrentImageContext();
 UIGraphicsEndImageContext();
  • UIGraphicsBeginImageContextWithOptions 该函数开始创建图片上下文,它有三个参数:
    size:想要渲染图片的大小尺寸
    opaque:所要创建图片的背景是否是不透明的。YES 背景则为黑色,NO 背景则为透明。
    scale:所要创建图片的缩放比例。如果设置为0 ,则和[UIScreen mainScreen].scale效果一样,随着手机屏幕分辨率改变。
  • 调用方法renderInContext:将view的layer渲染到当前的绘制的上下文中。(Renders the layer and its sublayers into the specified context.)
  • UIGraphicsGetImageFromCurrentImageContext:基于当前位图的上下文返回图像。
  • UIGraphicsEndImageContext:从堆栈顶部删除当前基于位图的图形上下文。

以上就是iOS的截图代码了。但是对于WKwebVIew(长图)来说,这个代码截不了完整的图片。因为WKwebView考虑到性能问题,并不会加载用户看不到的地方,所以会导致截图不完整。

WKWebView长截图

思路

这边先来说一下思路吧,我也是参考了网上很多实现方法总结的。我们可以看到WKWebView中有个子视图是WKScrollView。那么我们就可以通过拖动ScrollView来加载内容,与此同时截下图片。当ScrollView拖动到底之后,将全部截图拼接起来即可。

PS:当页面有悬浮栏时就会出现问题,在每一张截图中均会出现悬浮栏。目前我没有想到可以解决这个问题的方法,但思路大概是让WKwebVIew全部加载出来,然后进行截图。

实现

外部方法

/// 对WKWebView进行长截图(没有规避H5悬浮栏)
/// @param webView 需要进行截图的webView
/// @param completionHandler 截图完成回调
 - (void)snapshotForWKWebView:(WKWebView *)webView CaptureCompletionHandler:(void (^)(UIImage * _Nonnull))completionHandler {
    //1.添加遮罩层
    UIView *snapshotView = [webView snapshotViewAfterScreenUpdates:YES];
    snapshotView.frame = webView.frame;
    [webView.superview addSubview:snapshotView];
    //2.初始化数组
    self.imgArr = [NSMutableArray array];
    //3.进行截图操作
    CGPoint savedCurrentContentOffset = webView.scrollView.contentOffset;
    webView.scrollView.contentOffset = CGPointZero;
    [self createSnapshotForWKWebView:webView offset:0.0 remainingOffset_y:webView.scrollView.contentSize.height comletionBlock:^(UIImage *snapshotImg) {
        webView.scrollView.contentOffset = savedCurrentContentOffset;
        [snapshotView removeFromSuperview];
        completionHandler(snapshotImg);
    }];
}
  1. 为了让用户看不到我们截图滚动的操作,这里使用snapshotViewAfterScreenUpdates 方法来实现屏幕快照进行遮盖。
  2. 初始化imgArr数组,之后用来存放每一部分截图。
  3. 保存当前WKScrollView.contentOffset以便截图操作结束后还原“案发现场”。
  4. WKScrollView.contentOffset设置为CGPointZero,调用截图方法开始截图。

截图操作方法

/// 绘制WKWebView长截图
/// @param webView 所需要截图的WebView
/// @param offset_y 当前scollView的y偏移量
/// @param reOffset_y 剩余scollView的y偏移量
/// @param completeBlock 回调块
- (void)createSnapshotForWKWebView:(WKWebView *)webView offset:(float)offset_y remainingOffset_y:(float)reOffset_y comletionBlock:(void(^)(UIImage *snapshotImg))completeBlock
{
    //判断scrollView是否已经滚动到底
    if (reOffset_y>0) {
        //设置
        [webView.scrollView setContentOffset:CGPointMake(0, offset_y) animated:NO];
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(),^{
            //对页面进行截图操作
            UIGraphicsBeginImageContextWithOptions(webView.frame.size, YES, [UIScreen mainScreen].scale);
            [webView.layer renderInContext:UIGraphicsGetCurrentContext()];
            UIImage * img = UIGraphicsGetImageFromCurrentImageContext();
            UIGraphicsEndImageContext();
            //将截图添加进数组
            [self.imgArr addObject:img];
            //修改offsetY偏移量
            CGFloat newOffset_y = offset_y + webView.scrollView.frame.size.height;
            CGFloat newReOffset_y = reOffset_y - webView.frame.size.height;
            [self createSnapshotForWKWebView:webView offset:newOffset_y remainingOffset_y:newReOffset_y comletionBlock:completeBlock];
            
        });
    }else {
        //合成截图为最终截图
        UIView * containerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, webView.frame.size.width, webView.scrollView.contentSize.height)];
        CGFloat originYOfImgView = 0;
        for (int i = 0; i<self.imgArr.count; i++) {
            UIImageView * imgView = [[UIImageView alloc] initWithFrame:CGRectMake(0, originYOfImgView, webView.frame.size.width, webView.frame.size.height)];
            UIImage * img = self.imgArr[i];
            imgView.image = img;
            originYOfImgView += webView.frame.size.height;
            [containerView addSubview:imgView];
        }
        //添加合成视图
        [webView.superview addSubview:containerView];
        //处理最终合并截图
        UIGraphicsBeginImageContextWithOptions(containerView.frame.size, YES, [UIScreen mainScreen].scale);
        [containerView.layer renderInContext:UIGraphicsGetCurrentContext()];
        UIImage * img = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        //移除合成视图
        [containerView removeFromSuperview];
        //返回截图
        if (completeBlock) {
            completeBlock(img);
        }
    }
}

  1. 判断当前scrollView是否已经滚动到底部。
  2. 如果没滚动到底部,则再次设置scrollView.contentOffset到下一页进行截图。
  3. 这边给截图添加延迟,保证页面完全加载。截好的图片将放入数组。
  4. 如果scrollView已经到底部,则用一个容器视图,将所有的截图拼接并且展示。
  5. 最后再对容器视图进行截图操作,便可以得到完整的WKWebView页面截图了。

End

这个方法还是存在一定的问题,如果有大佬知道如何解决悬浮栏多次被截问题,请回复我~文章来源地址https://www.toymoban.com/news/detail-655249.html

到了这里,关于iOS-长截图 (学习记录)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【疯狂Java讲义】Java学习记录(IO流)

    IO:Input / Output 完成输入 / 输出 应用程序运行时——数据在内存中                        ←→                把数据写入硬盘(磁带)                                 内存中的数据不可持久保存 输入:从外部存储器(硬盘、磁带、U盘)把数据读入内存中。

    2024年02月07日
    浏览(37)
  • window debug ios webview

    在window上想要debug在ios的应用中的webview页面,毕竟页面是在安卓端和ios端都有webview的。安卓的页面使用edge的edge://inspect/#devices,手机开启调试模式就可以了。对于ios就没有办法,页面中已经使用了vconsole可以看到部分的信息,vconsole的信息也是没有chrome调试那么好。 在YouTub

    2024年02月12日
    浏览(33)
  • C++学习记录——삼십이 C++IO流

    C语言的printf和scanf无法很好的输入输出自定义类型,且还需要程序员自己确定类型,所以C++就引入了输入流和输出流,是设备和内存之间的沟通。 其实iostream是通过菱形继承实现的。cout,cerr,clog其实做得有时候没有区分 也都能打印出来。fstream和sstream是针对文件和字符串的

    2024年02月09日
    浏览(34)
  • 【iOS逆向与安全】原生程序与WebView交互

    WKWebView 是 iOS 应用中强大的组件,但如何在逆向工程中最好地利用它呢?本文将带您了解在逆向过程中遇到webview后的相关操作。这些技术将让您能够修改 WKWebView 行为,读写关键元素,接口拦截,并揭示更多有趣的可能性。 了解如何在 iOS 逆向工程中处理 WKWebView,包括 元素

    2024年02月02日
    浏览(54)
  • flutter ios webview不能打开http地址

    参考 1、iOS添加信任 webview_flutter 在使用过程中会iOS出现无法加载HTTP请求的情况, 但是Flutter 却可以加载HTTP请求。这就与两个的框架有关了,Flutter是独立于UIKit框架的。 解决方案就是在iOS 的info.plist中添加对HTTP的信任。 安卓的一些地址打不开 Flutter-Webview组件处理Scheme协议

    2024年02月11日
    浏览(38)
  • Linux学习记录——사십일 高级IO(2)--- Select型服务器

    select就是多路转接IO。select能以某种形式,等待多个文件描述符,只要有哪个fd有数据就可以读取并全部返回。就绪的fd,要让用户知道。select等待的多个fd中,一定有少量或者全部都准备好了数据。 nfds输入型参数,表示select等待的多个fd中,fd对应的数 + 1 剩下四个参数都是输

    2024年01月16日
    浏览(52)
  • STM32外设芯片驱动学习记录 —— (二) PCA9555 IO扩展芯片驱动开发

    一、芯片介绍 二、Datasheet解读 1.硬件说明 2.寄存器说明 3.通信过程 三、驱动代码编写 1.软件I2C驱动 2. PCA9555芯片驱动函数 总结         PCA9555可设置16路输入或输出口,I2C接口,用于IO扩展,3个硬件地址引脚寻址,工作电压:VCC(2.3V 至 5.5V)。 1)框图   INT:中断输出 A0,

    2024年02月11日
    浏览(49)
  • Linux学习记录——사십삼 高级IO(4)--- Epoll型服务器(1)

    poll依然需要OS去遍历所有fd。一个进程去多个特定的文件中等待,只要有一个就绪,就使用select/poll系统调用,让操作系统把所有文件遍历一遍,哪些就绪就加上哪些fd,再返回。一旦文件太多了,遍历效率就显而易见地低。epoll是为处理大批量句柄而作了改进的poll,句柄就是

    2024年01月18日
    浏览(50)
  • Linux学习记录——사십오 高级IO(6)--- Epoll型服务器(3)(Reactor)

    看完前两篇再看这篇,本篇将会写Reactor EpollServer.hpp中创建一个函数HandlerRequest,用它来做Recver函数的数据处理,也就是数据分析。 改一下回调函数,不向外暴露Connection类。 Main.cc中就不需要两个函数,一个计算函数就可以 处理数据那里再加上最后的步骤 回到Recver函数,调用

    2024年01月23日
    浏览(55)
  • Linux学习记录——사십사 高级IO(5)--- Epoll型服务器(2)(Reactor)

    本篇基于上篇代码继续改进,很长。关于Reactor的说明在后一篇 上面的代码在处理读事件时,用的request数组是临时的,如果有数据没读完,那么下次再来到这里,就没有这些数据了。所以得让每一个fd都有自己的缓冲区。建立一个Connection类,然后有一个map结构,让这个类和每

    2024年01月20日
    浏览(55)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包