有一種咱們常常能看到的頁面,上方是圖文混排的富文本內容,下方是評論列表。好比網易新聞詳情頁,簡書文章詳情頁。它們是怎麼實現的呢?一般是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.我和我家作前端的老公作了個公號,內容也會同時更新在那邊,歡迎來關注~