1. 程式人生 > >iOS 【野路子】獲取WKWebView內容高度做H5原生連接

iOS 【野路子】獲取WKWebView內容高度做H5原生連接

select cti ats 獲取頁面高度 attr cell 模式 posit length

前言:是這樣的,剛寫完上一篇文章還沒緩過神來,上一篇文章我還提到了,想和大家聊聊原生+H5如何無縫連接的故事.結果我朋友就給我發了兩篇他的作品.他的做法也都有獨到之處.好的文章都是這樣,讓你每次看都能有新的收獲,我們也都致力於寫一些能幫別人解決問題的文章,下面我用另一種方式來完美實現這個問題.畢竟之前大家都是根據UIWebView寫的,我來說說換成WK之後的區別,主題思路也不同哦~
插兩個鏈接,是我朋友的大家也可以做個對比

iOS 【終極方案】精準獲取webView內容高度,自適應高度
iOS 【奇巧淫技】獲取webView內容高度
iOS WKWebView 圖片點擊放大並左右滑動,類似微信/網易文章功能

首先先說應用場景吧,這樣大家可能更能接受一點

例1:一個頁面 分為上下兩個部分,上部分為文章,商品圖文介紹等(H5)一個web,下半部分是原生的列表(tableView)
那麽怎麽把H5和原生結合在一起呢,最簡單的思想就是把H5做成表頭,對吧.那麽獲取Web部分的真實高度就是最大的難點公關.

例2:上面是一個原生介紹,下面分為3部分,其中一部分是H5頁面的詳情介紹,一部分是評論列表,一部分是相關推薦等等,這樣,最合理的結構就是:上面作為一個Tabview的表頭,下面共用同一個tabview,將H5的web嵌入成某一種tableviewCell當中.那麽難點就是怎麽獲取Web這個cell的高度返回.

我就拿第二種來舉例子吧.畢竟第二種更復雜一些,而且例1 很多工程都實現了,我朋友的文章也能實現這個功能,第二種例子,我用WKWebView給大家提供一個新的思路.

嗶嗶叨叨了這麽多,下面開始說正題吧.

首先跟大家說一下,簡單的獲取contentSize 什麽的(網上一搜隨處可見的那幾個方法)我就不吐槽了,他們的應用場景太局限了,稍微在進行富文本編輯的時候 插入的圖片 尺寸 或者某些動圖之類的 都會導致你獲取的高度不準,然後界面UI惡心到不行.
那麽思路依舊是跟我上一篇文章一樣 利用JS註入來解決
首先從加載的時候開始
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if(self){
self.contentView.backgroundColor = NineColorOne;
[self creatSubviews];
}
return self;
}
- (void)creatSubviews
{
WKWebViewConfiguration *confifg = [[WKWebViewConfiguration alloc] init];
confifg.selectionGranularity = WKSelectionGranularityCharacter;
_webView = [[WKWebView alloc] initWithFrame:CGRectMake(14, 0, CurrentScreenWidth - 28, 1) configuration:confifg];
self.contentView.backgroundColor = NineColorOne;
// _webView.scalesPageToFit = NO;
_webView.scrollView.scrollEnabled=NO;
_webView.userInteractionEnabled = NO;
_webView.opaque = NO;
_webView.scrollView.bounces=NO;
_webView.backgroundColor=NineColorOne;
_webView.scrollView.decelerationRate=UIScrollViewDecelerationRateNormal;
[self.contentView addSubview:_webView];
}


我剛才說了,把web放在一個cell裏,那麽它的代理就要在VC裏面去簽.
大家註意到,_webView.scalesPageToFit = NO;這句話我屏蔽掉了,因為WKWebView是沒有這個屬性的 它和UIWebView不同,然而 如果不設置NO, WKWebView的默認效果和UIWebView.scalesPageToFit = YES是一樣的,這時候,你需要這段代碼:

<meta content=\"width=device-width, initial-scale=1.0, maximum-scale=3.0, user-scalable=0;\" name=\"viewport\" />
  • 1

這段代碼 註入在加載的時候
例如:

- (void)setDetail:(NSString *)detail
{
        if(!_detail){
                _detail = detail;
            if (_detail.length >0) {

                [_webView loadHTMLString:[NSString stringWithFormat:@"<meta content=\"width=device-width, initial-scale=1.0, maximum-scale=3.0, user-scalable=0;\" name=\"viewport\" />%@<div id=\"testDiv\" style = \"height:100px; width:100px\"></div>",_detail] baseURL:[NSURL fileURLWithPath: [[NSBundle mainBundle]  bundlePath]]];
                }
        }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

註意2點:
1.因為整體邏輯是 Web放在cell裏,加載完成後刷新tabview,那麽刷新的時候 走代理方法cellforrow,則cell會重新賦值,產生死鏈.所以在賦值時候要做基本處理
2.我在註入scalesPageToFit代碼的同時,似乎還加了一個div?對的,你沒有看錯.下面我就說一說,這個div是幹什麽用的

我們將目光切回到VC

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
         _webview = cell.webView;
        cell.webView.navigationDelegate = self;
        cell.webView.UIDelegate = self;
        cell.selectionStyle = 0;
        cell.detail = @"這裏就是你要加載的html";
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

這是代理方法裏面cell的部分代碼.可以看到 代理我們都簽在了VC裏
緊接著看加載完成方法

- (void)webView:(WKWebView *)webView didFinishNavigation:(null_unspecified WKNavigation *)navigation
{

    [webView evaluateJavaScript:@"document.getElementById(\"testDiv\").offsetTop"completionHandler:^(id _Nullable result,NSError * _Nullable error) {
        //獲取頁面高度,並重置webview的frame
        CGFloat lastHeight  = [result doubleValue];
        webView.frame = CGRectMake(14, 0, CurrentScreenWidth - 28, lastHeight);
        webHeight = lastHeight;
        [self.tableView beginUpdates];
        [self.tableView endUpdates];
    }];



}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

註意看一下這裏,首先WK的JS註入方法有變化,其次就是你發現我取web的高度利用了我剛才在加載HTML時註入的div塊
這樣,不管你的網頁是什麽樣的,在尾部加一個div它的位置永遠是你需要的高度.(一定要註意這段代碼不加的話 獲取的高度同樣不準哦)

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    if(_type == 0){
        return webHeight;
        }// 當前tableview是加載web狀態時 cell返回高度
  • 1
  • 2
  • 3
  • 4
  • 5

那麽這個時候 你還會發現,滾動tableView時,web顯示內容沒有變化!!!
對,這就是WKWebView的另一個區別,由於WKWebView采用的lazy加載模式,所在的scrollView的滾動被禁用,導致被嵌套的WKCompositingView不進行數據加載。

- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
    // 判斷webView所在的cell是否可見,如果可見就layout
    NSArray *cells = self.tableView.visibleCells;
    for (UITableViewCell *cell in cells) {
        if ([cell isKindOfClass:[UITableViewCell class]]) {
            UITableViewCell *webCell = (UITableViewCell *)cell;
            [webCell.webView setNeedsLayout];
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

你需要加上這個代碼.

嗯這時候,H5和原生就完美的無縫連接了.
這些東西也並非我一個人獨立想出來的,在這裏也對我的好朋友–徐陽 表示由衷的感謝,是他給我提供了很多思路.對,就是上面我推薦文章的那個人.

還不知道下一篇想寫什麽,最近忽然又對寫博客起了興趣.

iOS 【野路子】獲取WKWebView內容高度做H5原生連接