UIWebView與tableView嵌套的內存問題及解決方案

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

程序員夫婦的平常
程序員夫婦的平常
相關文章
相關標籤/搜索