有一种咱们常常能看到的页面,上方是图文混排的富文本内容,下方是评论列表。好比网易新闻详情页,简书文章详情页。它们是怎么实现的呢?一般是webView+tableView的组合,由于文章和新闻的编辑后台生成的就是html文本,用webView去渲染能最简单高效优美地呈现内容。html
具体到实现细节,webView与native的交互方式,本地静态html模板缓存,图片占位等,每家都有本身的方案,有兴趣了解的话我会在之后的文章里介绍咱们的方案。本文主要介绍咱们是如何去嵌套这两个控件的。前端
简书的开发人员在《UIWebView与UITableView的嵌套方案》这篇文章里介绍了三种方案,其中第一种方案是不少人都会采用的——把webView做为tableView的headView,并在拿到webview实际内容高度的时候重设headView的高度。这样一来,滚动全交给tableView,把webview的滚动禁用掉,那么总体滑动就会很是和谐。程序员
看上去很美,可是上面的作法是有代价的,当webview内容不少,多图多文,webview的frame.size.height会变得很是大,若是留意这时候的内存状况的话,相同的内容在size.height更大的webview里内存会高出不少。对于图文内容很是多的app来讲,这个方案存在内存爆炸的隐患。web
那么,如何在不改变webView高度的状况下,让总体滑动和谐,视觉上webview和tableView无缝衔接呢?浏览器
简书开发人员的作法是把tableView放在webView里,并禁用webView和tableView的滑动,彻底本身去实现滑动功能,文章里有源码地址,有兴趣的能够去看看,处理起来挺复杂,并且实际应用中,tableView每每是分页加载的列表,这里的上滑加载更多还要去实现,而且在tableView内容变化以后还要去更新webView的size,他们的demo里没有提到这个。缓存
放弃手写滑动,从新审视问题:有没有这样一种办法,不改变webView高度的状况下,经过滑动tableView来让浏览器里面的内容跟着滑动起来?有的呀!“透视”!bash
咱们仍是依靠tableView的headView,headView的高度跟着浏览器的内容高度而变,可是这个headView不直接设为webView,而是个高度等于浏览器高度,但自己透明的一个view,而后把webView放置在整个tableView的下面,这样webView的内容实际上就透视出来了,让人“看获得但摸不着”。服务器
self.htmlWebView = [[UIWebView alloc]initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height-50-44-STATUS_BAR_HEIGHT)];
_htmlWebView.scrollView.scrollsToTop = NO;
_htmlWebView.scrollView.scrollEnabled = NO;
_htmlWebView.delegate = self;
[_htmlWebView setBackgroundColor:[UIColor grayBackgroundColor]];
[_htmlWebView setOpaque:NO];
[self.view addSubview:_htmlWebView];
[self.view sendSubviewToBack:_htmlWebView];
self.tableHeadView = [[UIView alloc]initWithFrame:self.htmlWebView.frame];
[_tableHeadView setBackgroundColor:[UIColor clearColor]];
self.tableView.tableHeaderView = _tableHeadView;
self.tableView.backgroundColor = [UIColor clearColor];复制代码
接下来的任务就是经过操做上层的tableView去滑动底层的webView,一样很简单,看代码。app
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
if ([scrollView isKindOfClass:[UITableView class]]) {
self.htmlWebView.scrollView.contentOffset = scrollView.contentOffset;
}
}复制代码
- (void)_resizeHeadView {
[_tableHeadView setFrame:CGRectMake(0, 0, self.tableView.frame.size.width, self.webviewHeight)];
[self.tableView beginUpdates];
[self.tableView setTableHeaderView:self.tableHeadView];
[self.tableView endUpdates];
}复制代码
顺便,提一下webview内容高度获取的问题,为了用户体验,咱们不可能等到webView彻底finishLoad才去更新headView的高度,可能有的团队的作法是根据内容加载的进度,动态去改变这个高度,可是这会带来页面内容哐哐哐往下掉的问题,因此咱们项目的作法是由服务器下发带图片尺寸的html文本,文本请求是很快的,咱们在页面一进来就能根据html文本计算出预期的内容高度,把headView的高度调整到位,其中这个计算交给js。ui
如下是webView通知native“已经计算好内容高度,去更新吧~”的代码。
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
if ([request.URL.scheme isEqualToString:@"bolomegetwebviewheight"]) {
self.webviewHeight = [request.URL.host floatValue];
if (!fEqualTo(CGRectGetHeight(self.htmlWebView.frame), self.webviewHeight)) {
[self _resizeHeadView];
}
return NO;
}
return YES;
}复制代码
探讨到这儿,后面有空写个完整demo,还有其余方案吗,欢迎交流~
PS.我和我家作前端的老公作了个公号,内容也会同时更新在那边,欢迎来关注~