關(guān)于webView截取長圖問題

需求背景:由客戶端截取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)一些小問題


調(diào)試的工具按鈕截取好幾個
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),才能保證截圖正常。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容