需求还原:
如图所示:
整个页面分为上下两部分:上部分是普通的view,下部分是一个webview,加载H5文本。需求是这两部分要同时滚动。
思路
把上下两部分放在一个scrollView上,设置webview不可滚动并且让webview高度自适应内容(webView.height = webView.scrollView.contentSize.height
),再调整scrollView的contentSize。
实现方法
在webview的代理方法webViewDidFinishLoad:
中做相应处理即可:
- (void)webViewDidFinishLoad:(UIWebView *)webView{
// webView加载完成,让webView高度自适应内容
self.contentWebView.height = self.contentWebView.scrollView.contentSize.height;
self.contentScrollView.contentSize = CGSizeMake(screenWidth, self.contentWebView.maxY);
}
存在的问题
没过多久,测试妹纸就反馈有时webview只显示了部分内容。我就纳闷了,我的思路和代码都是完美无bug的,不应该有问题啊但是后面测试妹纸不停的向我反馈这个问题,我知道,肯定是自己的代码有问题了。把代码反复看了几遍,最终定位到webViewDidFinishLoad :
这个方法上。于是上网查询,终于知道了原因:
我想当然的认为webViewDidFinishLoad :
回调之时就是webview加载完成之日(有多少人被坑过)。实际上并不是,这里就不做过多讨论了,详情自己上网查询(网页重定向)。只需要记住:webViewDidFinishLoad :
回调的时候并不能说明webview加载完成
解决问题
知道问题所在后解决问题就简单了:需要找准webview加载完成的那个点。结合网上前辈提供的方法,我给UIWebView写了一个category,用来判断webview是不是真正的完成了加载。代码如下:
/** 判断webView是否完全加载完数据 */
- (BOOL)isFinishLoading{
NSString *readyState = [self stringByEvaluatingJavaScriptFromString:@"document.readyState"];
BOOL complete = [readyState isEqualToString:@"complete"];
if (complete && !self.isLoading) {
return YES;
}else{
return NO;
}
}
这就在原来的基础上多了一个判断:
- (void)webViewDidFinishLoad:(UIWebView *)webView{
// webView加载完成,让webView高度自适应内容
if ([webView isFinishLoading] == YES) {
self.contentWebView.height = self.contentWebView.scrollView.contentSize.height;
self.contentScrollView.contentSize = CGSizeMake(screenWidth, self.contentWebView.maxY);
}
}
这样,webview高度自适应内容就完成了。
优化
虽然功能是完成了,但是却不怎么完美:我们初始化webview的时候会给webview设置一个frame,如果webview的height设置低了,加载数据期间将只能显示部分内容;如果webview高度设置太大,加载数据期间下方又是一片空白。如果能动态持续的改变webview的高度,那这个问题也就解决了。方法就是:实时监听webview的scrollView的contentSize的变化,然后调整webview的高度。代码如下:
// webview高度自适应内容
[RACObserve(self.contentWebView.scrollView, contentSize) subscribeNext:^(id x) {
self.contentWebView.height = self.contentWebView.scrollView.contentSize.height;
self.contentScrollView.contentSize = CGSizeMake(screenWidth, self.contentWebView.maxY);
}];
这是最简单同时也是最完美的实现方法(用这个方法就不需要再在webview的代理方法里做处理了)。什么你没用RAC?好吧那你就用传统的KVO咯。建议没学RAC的去了解一下,有时候对于简化代码还是很有帮助的。
至此,UIWebView高度自适应内容以及持续自适应就完美实现了。讲了这么多其实核心就是监听webView.scrollView.contentSize的变化然后调整webView的高度
WKWebView处理方式一样
使用KVO:
#pragma mark - KVO
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
self.webView.height = self.webView.scrollView.contentSize.height;
}
使用WKWebView时你可能会遇到的问题
1. 字体相比UIWebView更小了
2.底部大片空白
解决方法:稍微延迟一下
#pragma mark - KVO
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
self.webView.height = self.webView.scrollView.contentSize.height;
});
}
网友评论