Objective-C迁移UIWebView到WKWebView,如何实现高度自适应内容?
WKWebView 高度自适应内容解决方案(Objective-C)
核心问题原因
WKWebView 无法像 UIWebView 那样通过 sizeThatFits: 获取内容高度,必须通过 JavaScript 注入的方式获取页面实际内容高度,再更新约束常量。
具体实现步骤
1. 配置 WKWebView 并设置代理
在 TMAnswerView.m 的初始化方法中,给 WKWebView 设置 navigationDelegate,同时禁用内部滚动(如果不需要内容滚动):
- (instancetype)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init]; self.webView = [[WKWebView alloc] initWithFrame:CGRectZero configuration:config]; self.webView.navigationDelegate = self; self.webView.scrollView.scrollEnabled = NO; // 禁用滚动,确保高度自适应生效 self.webView.scrollView.bounces = NO; // 添加布局约束(假设已绑定 heightOfWebView 高度约束) [self.webView setTranslatesAutoresizingMaskIntoConstraints:NO]; [self addSubview:self.webView]; // 补充你的其他约束(如 leading、trailing、top) self.heightOfWebView = [NSLayoutConstraint constraintWithItem:self.webView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:0]; [self addConstraint:self.heightOfWebView]; } return self; }
2. 页面加载完成后获取内容高度
实现 WKNavigationDelegate 的页面加载完成回调,通过 JS 获取内容高度并更新约束:
#pragma mark - WKNavigationDelegate - (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation { // 执行 JS 获取页面实际高度,优先取 document.documentElement.scrollHeight 适配更多场景 [webView evaluateJavaScript:@"Math.max(document.body.scrollHeight, document.documentElement.scrollHeight)" completionHandler:^(id _Nullable result, NSError * _Nullable error) { if (!error && result) { CGFloat contentHeight = [result doubleValue]; // 更新高度约束常量 self.heightOfWebView.constant = contentHeight; // 强制刷新布局 [self layoutIfNeeded]; } }]; }
3. 处理图片/动态内容加载后的高度变化
如果页面包含图片或动态加载内容,仅靠页面加载完成回调可能获取到的高度不准确,可通过注入 JS 监听页面加载完成(包括图片):
// 在初始化 WKWebViewConfiguration 时添加 UserScript WKUserScript *heightScript = [[WKUserScript alloc] initWithSource:@"window.addEventListener('load', function() { window.webkit.messageHandlers.webViewHeightCallback.postMessage(Math.max(document.body.scrollHeight, document.documentElement.scrollHeight)); });" injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:YES]; [config.userContentController addUserScript:heightScript]; // 添加消息处理器 [config.userContentController addScriptMessageHandler:self name:@"webViewHeightCallback"];
然后实现 WKScriptMessageHandler 协议方法:
#pragma mark - WKScriptMessageHandler - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message { if ([message.name isEqualToString:@"webViewHeightCallback"]) { CGFloat contentHeight = [message.body doubleValue]; self.heightOfWebView.constant = contentHeight; [self layoutIfNeeded]; } } // 记得在销毁时移除消息处理器,避免循环引用 - (void)dealloc { [self.webView.configuration.userContentController removeScriptMessageHandlerForName:@"webViewHeightCallback"]; }
注意事项
- 确保 WKWebView 的
scrollEnabled设为 NO,否则内容会滚动,高度自适应效果失效。 - 如果 WKWebView 设置了内边距(
contentInset),需要在计算高度时把内边距值加入约束常量。 - 若页面存在动态内容(如 AJAX 加载),可进一步注入 JS 使用
MutationObserver监听 DOM 变化,实时更新高度。
内容的提问来源于stack exchange,提问作者Diego Perez
相关产品推荐
相关产品推荐

