需求背景:由客戶端截取webView頁面所有內(nèi)容并生成圖片分享或者保存本地
思路:
GitHub找到一個第三方的demo(ZSSnapshotKit),經(jīng)測試功能滿足,集成使用
實(shí)現(xiàn)方式就是截取每屏圖片拼接
//在截圖之前先將用戶看到的當(dāng)前頁面截取下來,作為一張圖片擋住接下來所執(zhí)行的截取操作,
//并且在執(zhí)行完截圖操作后,將截取的遮蓋圖片銷毀。
UIImageView *coverImageView = [[UIImageView alloc] initWithFrame:self.frame];
coverImageView.image = [self takeSnapshotOfVisibleContent];
coverImageView.backgroundColor = [UIColor redColor];
[self.superview addSubview:coverImageView];
[self.superview bringSubviewToFront:coverImageView];
//分頁繪制內(nèi)容到ImageContext
CGPoint originalOffset = self.contentOffset;
// 當(dāng)contentSize.height<bounds.height時,保證至少有1頁的內(nèi)容繪制
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();
}
}
});
}
問題:
目前一般的長圖都可以截取,但是有吸頂吸底的則會出現(xiàn)一些小問題
bug:
經(jīng)反復(fù)測試,當(dāng)屏幕滑動未停止時,點(diǎn)擊截圖按鈕,截圖有問題如下:
解決:
由于未發(fā)現(xiàn)bug復(fù)現(xiàn)路徑,耽誤很長時間復(fù)現(xiàn),后證實(shí)只要屏幕滾動未停止,截圖就出問題,嘗試過修改scrollView坐標(biāo),重新定位,不行;所以換個思路,截圖之前讓scrollView停止?jié)L動(非禁止)
// 加了這句代碼,停止?jié)L動
[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);
}];
結(jié)語:
好了,說到底還就是一句代碼的事!
知識點(diǎn)補(bǔ)充:
[iOS關(guān)于setContentOffset的一些細(xì)節(jié)問題]
在UIScrollView,setContentOffset方法的功能是跳轉(zhuǎn)到你指定內(nèi)容的坐標(biāo),
setContentOffset有兩種方法:setContentOffset:和setContentOffset:animated:
但是兩者還是有點(diǎn)差異的:
setContentOffset:animated: 這種方法,無論animated為YES還是NO, 都會等待scrollView的滾動結(jié)束以后才會執(zhí)行,也就是當(dāng)isDragging和isDecelerating為YES的時候,會等待滾動完成才執(zhí)行上面的方法。
setContentOffset:這種方法則不受scrollView是否正在滾動的限制
所以上面的方法可以達(dá)到暫停scrollView滾動的效果,只有頁面靜止?fàn)顟B(tài),才能保證截圖正常。