关于webView截取长图问题

需求背景:由客户端截取webView页面所有内容并生成图片分享或者保存本地

思路:

GitHub找到一个第三方的demo(ZSSnapshotKit),经测试功能满足,集成使用
实现方式就是截取每屏图片拼接

//在截图之前先将用户看到的当前页面截取下来,作为一张图片挡住接下来所执行的截取操作,
    //并且在执行完截图操作后,将截取的遮盖图片销毁。
    UIImageView *coverImageView = [[UIImageView alloc] initWithFrame:self.frame];
    coverImageView.image = [self takeSnapshotOfVisibleContent];
    coverImageView.backgroundColor = [UIColor redColor];
    [self.superview addSubview:coverImageView];
    [self.superview bringSubviewToFront:coverImageView];
    
    //分页绘制内容到ImageContext
    CGPoint originalOffset = self.contentOffset;
    
    // 当contentSize.height self.bounds.size.height) {
        pageNum = (NSInteger)floorf(self.contentSize.height / self.bounds.size.height);
    }
    
    UIColor *backgroundColor = self.backgroundColor;
    if (backgroundColor == nil) backgroundColor = UIColor.whiteColor;
    
    UIGraphicsBeginImageContextWithOptions(self.contentSize, YES, 0);
    CGContextRef context = UIGraphicsGetCurrentContext();
    if (context == nil) {
        [coverImageView removeFromSuperview];
        completion(nil);
        return;
    }
    
    CGContextSetFillColorWithColor(context, backgroundColor.CGColor);
    CGContextSetStrokeColorWithColor(context, backgroundColor.CGColor);
    
    [self drawScreenshotOfPageContent:0 maxIndex:pageNum completion:^{
        UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        self.contentOffset = originalOffset;
        [coverImageView removeFromSuperview];
        if (completion) {
            completion(image);
        }
    }];



- (void)drawScreenshotOfPageContent:(NSInteger)index maxIndex:(NSInteger)maxIndex completion:(void(^)(void))completion {
    
    [self setContentOffset:CGPointMake(0, index * self.frame.size.height)];
    CGRect pageFrame = CGRectMake(0, index * self.frame.size.height, self.bounds.size.width, self.bounds.size.height);
    
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [self drawViewHierarchyInRect:pageFrame afterScreenUpdates:YES];
        if (index < maxIndex) {
            [self drawScreenshotOfPageContent:index+1 maxIndex:maxIndex completion:completion];
        }else {
            if (completion) {
                completion();
            }
        }
    });
    
}
问题:

目前一般的长图都可以截取,但是有吸顶吸底的则会出现一些小问题


调试的工具按钮截取好几个
bug:

经反复测试,当屏幕滑动未停止时,点击截图按钮,截图有问题如下:


削顶,中间拼接有重叠错乱情况
解决:

由于未发现bug复现路径,耽误很长时间复现,后证实只要屏幕滚动未停止,截图就出问题,尝试过修改scrollView坐标,重新定位,不行;所以换个思路,截图之前让scrollView停止滚动(非禁止)

  // 加了这句代码,停止滚动
    [self.webView.scrollView setContentOffset:self.webView.scrollView.contentOffset animated:NO];
    // 开始截图
    [self.webView.scrollView asyncTakeSnapshotOfFullContent:^(UIImage * _Nullable image) {
        [SVProgressHUD dismiss];
        //保存截图到照片
        UIImageWriteToSavedPhotosAlbum(image, self, @selector(completedWithImage:error:context:), NULL);
    }];

结语:

好了,说到底还就是一句代码的事!

知识点补充:
[iOS关于setContentOffset的一些细节问题]

在UIScrollView,setContentOffset方法的功能是跳转到你指定内容的坐标,
setContentOffset有两种方法:setContentOffset:和setContentOffset:animated:
但是两者还是有点差异的:
setContentOffset:animated: 这种方法,无论animated为YES还是NO, 都会等待scrollView的滚动结束以后才会执行,也就是当isDragging和isDecelerating为YES的时候,会等待滚动完成才执行上面的方法。
setContentOffset:这种方法则不受scrollView是否正在滚动的限制
所以上面的方法可以达到暂停scrollView滚动的效果,只有页面静止状态,才能保证截图正常。

你可能感兴趣的:(关于webView截取长图问题)