需求背景:由客户端截取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<bounds.height时,保证至少有1页的内容绘制
NSInteger pageNum = 1;
if (self.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滚动的效果,只有页面静止状态,才能保证截图正常。
网友评论