UITableViewCell中WKWebView内容更新时如何获取正确contentHeight?
解决UITableViewCell中WKWebView内容动态更新时实时获取高度的问题
问题核心
在UITableViewCell内集成WKWebView时,初始高度可通过evaluateJavaScript获取指定div的scrollHeight解决,但网页内点击按钮展开弹窗后,无法实时捕获高度变化——KVO监听scrollView.contentSize仅在滚动后才触发,无法及时更新Cell高度。
最优解决方案:网页主动通知Native高度变化
利用WebKit的消息机制,让网页在DOM高度变化时主动向Native发送最新高度,这是最可靠的方式(网页自身清楚内容变化时机)。
1. 注入DOM监听脚本到WKWebView
初始化WKWebView时,注入MutationObserver脚本监听目标div的高度变化:
// 配置WKWebView内容控制器 let contentController = WKUserContentController() // 注入监听DOM变化的脚本 let heightObserverScript = """ const targetNode = document.getElementById('svelte'); if (targetNode) { // 监听目标div的属性、子节点及后代变化 const observerConfig = { attributes: true, childList: true, subtree: true }; const observer = new MutationObserver(() => { const latestHeight = targetNode.scrollHeight; // 向Native发送最新高度 window.webkit.messageHandlers.webViewHeightObserver.postMessage(latestHeight); }); observer.observe(targetNode, observerConfig); } """ let userScript = WKUserScript(source: heightObserverScript, injectionTime: .atDocumentEnd, forMainFrameOnly: true) contentController.addUserScript(userScript) // 添加Native消息处理器 contentController.add(self, name: "webViewHeightObserver") // 初始化WKWebView let webConfig = WKWebViewConfiguration() webConfig.userContentController = contentController let webView = WKWebView(frame: .zero, configuration: webConfig)
2. Native接收高度更新并刷新Cell
实现WKScriptMessageHandler协议,接收网页发送的高度数据并更新UITableView:
extension RichContentTableViewCell: WKScriptMessageHandler { func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { guard message.name == "webViewHeightObserver", let newHeight = message.body as? CGFloat else { return } // 更新全局高度缓存 RichContentTableViewCell.maximumHeight = newHeight // 刷新当前Cell的高度 if let tableView = self.superview as? UITableView { tableView.beginUpdates() tableView.endUpdates() } } }
3. 清理资源(避免内存泄漏)
在Cell销毁时移除消息处理器:
deinit { webView.configuration.userContentController.removeScriptMessageHandler(forName: "webViewHeightObserver") }
为什么KVO方案失效?
WKWebView的scrollView.contentSize更新依赖WebKit内部布局流程,DOM变化后不会立即同步到Native层的scrollView属性——只有滚动操作触发强制布局时,contentSize才会更新,因此KVO无法实时捕获高度变化。
备选方案(不推荐,仅作补充)
如果无法修改网页脚本,可尝试在网页按钮点击触发的Native回调中,主动调用evaluateJavaScript获取最新高度:
// 假设通过WKNavigationDelegate捕获按钮点击事件后,主动获取高度 func getLatestWebViewHeight() { webView.evaluateJavaScript("document.getElementById('svelte').scrollHeight") { [weak self] result, error in guard let self = self, let height = result as? CGFloat else { return } RichContentTableViewCell.maximumHeight = height self.superview?.beginUpdates() self.superview?.endUpdates() } }
内容的提问来源于stack exchange,提问作者Ram
相关产品推荐
相关产品推荐

