What 资讯类型下tableview嵌套wkwebview
开发的过程中,我们难免辉遇到tableview嵌套wkwebview的情况,基本使用tableviewHeader或者cell作为容器承载wkwebview但是如果wkwebview的高度计算不对的话,那么恭喜你,你会遇到各种各样无止境的bug
Why
- iOS13下使用
didFinish KVO获取高度的问题:
在之前我们通常使用wkwebview的代理方法或者KVO获取高度,但是这里存在的问题是:
didFinish获取的高度有时是内容并未完全加载完成的高度,那么此时获取的高度肯定是不准确的;KVO那么是通过观察者的方式获取的高度,它在iOS13下首先表现的问题就是获取的高度偏大,显示的视图内容下方会留白,而且因为KVO是一个持续监听的过程,我们也无从判断什么时候什么情况下的高度是正确的;而且还有一个重要的问题是如果wkwebview内容高度计算偏小,那么你就会遇到tableview和wkwebview的手势冲突问题,别问为什么,问多了都是泪👿
How
在实际解决的过程中,我也是饱览群书(各种google),最后找到了一个解决办法(其实之前就看到了,感觉不靠谱...😭)
原文:Monitor resizing of the document.body
var shouldListenToResizeNotification = false
lazy var webView:WKWebView = {
//Javascript string
let source = "window.onload=function () {window.webkit.messageHandlers.sizeNotification.postMessage({justLoaded:true,height: document.body.scrollHeight});};"
let source2 = "document.body.addEventListener( 'resize', incrementCounter); function incrementCounter() {window.webkit.messageHandlers.sizeNotification.postMessage({height: document.body.scrollHeight});};"
//UserScript object
let script = WKUserScript(source: source, injectionTime: .atDocumentEnd, forMainFrameOnly: true)
let script2 = WKUserScript(source: source2, injectionTime: .atDocumentEnd, forMainFrameOnly: true)
//Content Controller object
let controller = WKUserContentController()
//Add script to controller
controller.addUserScript(script)
controller.addUserScript(script2)
//Add message handler reference
controller.add(self, name: "sizeNotification")
//Create configuration
let configuration = WKWebViewConfiguration()
configuration.userContentController = controller
return WKWebView(frame: CGRect.zero, configuration: configuration)
}()
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
guard let responseDict = message.body as? [String:Any],
let height = responseDict["height"] as? Float else {return}
if self.webViewHeightConstraint.constant != CGFloat(height) {
if let _ = responseDict["justLoaded"] {
print("just loaded")
shouldListenToResizeNotification = true
self.webViewHeightConstraint.constant = CGFloat(height)
}
else if shouldListenToResizeNotification {
print("height is \(height)")
self.webViewHeightConstraint.constant = CGFloat(height)
}
}
}
使用SnapKit修改约束后立即更新视图
1.约束立即生效必须使用remakeConstraints 2.调用其父视图的setNeedsLayout()和layoutIfNeeded()
headerUIView.addSubview(myWebView)
myWebView.snp.remakeConstraints { (make) in
make.top.equalToSuperview().offset(ConstantsHelp.topMargin/2).priorityHigh()
make.left.right.equalToSuperview()
make.height.equalTo((Device().orientation == Device.Orientation.portrait ? self.webViewHeightPortrait : self.webViewHeightLandscape) ).priorityHigh()
}
UIView.animate(withDuration: 0.5) {
self.headerUIView.setNeedsLayout()
self.headerUIView.layoutIfNeeded()
}