前言
由于项目需要,新近实现了一个长截图库 SnapshotKit。其中,需要支持 UIWebView
、WKWebView
组件生成长截图。为了实现这个特性,查阅了很多资料,同时也做了不同的新奇思路尝试,最终实现了一个新的、取巧的技术方案。
以下主要总结了在“WebView生成长截图”需求方面,“网上已有方案”和“我的全新方案”的各自实现要点和优缺点。
WebView生成长截图的已有方案
根据 Google 所搜索到的资料,目前iOS WebView生成长截图的方案主要有2种:
- 方案一:修改Frame,截图组件
- 方案二:分页截图组件内容,合成长图
下面将会简述方案一和方案二的具体实现。
方案一:修改Frame,截图组件
方案一的实现要点在于:修改 webView.scrollView
的 frameSize
为 contentSize
,然后对整个 webView.scrollView
进行截图。
不过,这个方案只适用 UIWebView
组件,因为其是一次性加载网页所有的内容。而 WKWebView
组件,为了节省内存,加载网页内容时,只加载可视部分——这一点类似 UITableView
组件。在修改webView.scrollView
的 frameSize
后,立即执行了截图操作, 这时候,WKWebView
由于还没把网页的内容加载出来,导致生成的长截图是空白的。
方案一核心代码如下:
extension UIScrollView {
public func takeSnapshotOfFullContent() -> UIImage? {
let originalFrame = self.frame
let originalOffset = self.contentOffset
self.frame = CGRect.init(origin: originalFrame.origin, size: self.contentSize)
self.contentOffset = .zero
let backgroundColor = self.backgroundColor ?? UIColor.white
UIGraphicsBeginImageContextWithOptions(self.bounds.size, true, 0)
guard let context = UIGraphicsGetCurrentContext() else {
return nil
}
context.setFillColor(backgroundColor.cgColor)
context.setStrokeColor(backgroundColor.cgColor)
self.drawHierarchy(in: self.bounds, afterScreenUpdates: true)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
self.frame = originalFrame
self.contentOffset = originalOffset
return image
}
}
复制代码
测试代码:
// example code
private func takeSnapshotOfUIWebView() {
let image = self.webView.scrollView.takeSnapshotOfFullContent()
// 处理image
}
复制代码
方案二:分页截图组件内容,合成长图
方案二的实现要点在于:分页滚动WebView组件的内容,然后生成分页截图,最后把所有分页截图合成一张长图。
这个方案适用于 UIWebView
组件和 WKWebView
组件。
方案二核心代码如下: