UITableView中加载WKWebView,高度计算问题

一般情况下在UITableView的header或cell中加载webview,需要动态计算webview的内容高度,然后刷新tableview,那么接下来问题的重点就是如何准确的拿到webview的内容高度了

webview加载分两种:1、加载静态HTML,2、加载动态HTML。
两者在高度计算上是有区别的,下面就针对这两种进行讨论。

一、加载动态HTML

[ 思路1:从WKWebview的加载完成代理方法中着手]

代码如下:

- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {
    [webView evaluateJavaScript:@"document.body.offsetHeight" completionHandler:^(id _Nullable result,NSError * _Nullable error) {
        //1.获取页面高度,并重新计算webview的高度
        
        //2.缓存页面高度

       //3.tableview update 
    }];
}

但是,很可惜,这里获取的高度有时不精确,于是,采用了另一种方法。

[ 思路2:使用KVO监听webView.scrollView的contentSize]

code:
cell的方法

  • cell初始化方法
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {
        UIView *superView = self.contentView;
        superView.backgroundColor = [UIColor blueColor];
        WKWebView *webView = [[WKWebView alloc] initWithFrame:superView.bounds];
        webView.scrollView.scrollEnabled = NO;//禁用webView滑动
        webView.scrollView.userInteractionEnabled = NO;
//自适应宽高,这句要加
        webView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
       // webView.navigationDelegate = self;
        _webView = webView;
        [superView addSubview:_webView];
    //监听webView.scrollView的contentSize属性
        [_webView.scrollView addObserver:self forKeyPath:@"contentSize" options:NSKeyValueObservingOptionNew context:nil];
    }
    return self;
}
  • KVO监听处理
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    if ([keyPath isEqualToString:@"contentSize"]) {
        __weak typeof(self) weakSelf = self;
//执行js方法"document.body.offsetHeight" ,获取webview内容高度
        [_webView evaluateJavaScript:@"document.body.offsetHeight" completionHandler:^(id _Nullable result, NSError * _Nullable error) {
            CGFloat contentHeight = [result floatValue];
            if (weakSelf.webHeightChangedCallback) {
                weakSelf.webHeightChangedCallback(contentHeight);
            }
        }];
    }
}
  • 移除kvo监听
- (void)dealloc
{
    [_webView.scrollView removeObserver:self forKeyPath:@"contentSize"];
}
  • tableview部分
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (indexPath.row == 1) {
        return _webHeight;//web高度,全局属性
    }
    return 44;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (indexPath.row == 1) {
        WebTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:NSStringFromClass(WebTableViewCell.class)];
        if (!cell) {
            cell = [[WebTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:NSStringFromClass(WebTableViewCell.class)];
        }
        __weak typeof(self) weakSelf = self;
        cell.webHeightChangedCallback = ^(CGFloat webHeight) {
            __strong typeof(self) strongSelf = weakSelf;
            if (strongSelf->_webHeight < webHeight) {//当缓存的高度小于返回的高度时,更新缓存高度,刷新tableview
                strongSelf->_webHeight = webHeight;
                [weakSelf.tableView beginUpdates];
                [weakSelf.tableView endUpdates];
            }
        };
        return cell;
    }
    return nil;
}

//去除web页底部空白
- (void)scrollViewDidScroll:(UIScrollView *)scrollView { // 判断webView所在的cell是否可见,如果可见就layout
    NSArray *cells = self.tableView.visibleCells;
    for (UITableViewCell *cell in cells) {
        if ([cell isKindOfClass:[WebTableViewCell class]]) {
            WebTableViewCell *webCell = (WebTableViewCell *)cell;
            [webCell.webView setNeedsLayout];
        }
    }
}

二、加载静态HTML

和动态HTML类似,需要监听高度

 [_webView.scrollView addObserver:self forKeyPath:contentSizeKey options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:nil];

懒加载webview

- (WKWebView *)webView{
    if (!_webView) {
        //以下代码适配大小
        NSString *jScript = @"var meta = document.createElement('meta'); meta.setAttribute('name', 'viewport'); meta.setAttribute('content', 'width=device-width'); document.getElementsByTagName('head')[0].appendChild(meta);";
        WKUserScript *wkUScript = [[WKUserScript alloc] initWithSource:jScript injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:YES];
        WKUserContentController *wkUController = [[WKUserContentController alloc] init];
        [wkUController addUserScript:wkUScript];
        WKWebViewConfiguration *wkWebConfig = [[WKWebViewConfiguration alloc] init];
        wkWebConfig.userContentController = wkUController;
        _webView = [[WKWebView alloc] initWithFrame:CGRectMake(0, 0, ScreenW, 0) configuration:wkWebConfig];
        //禁用scrollview的交互
        _webView.scrollView.scrollEnabled = NO;
        _webView.scrollView.userInteractionEnabled = NO;
        _webView.navigationDelegate = self;
        _webView.scrollView.delegate = self;
       
        [_webView addSubview:self.indicatorView];
        //高度监听
        [_webView.scrollView addObserver:self forKeyPath:contentSizeKey options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:nil];
        [self.contentView addSubview:_webView];
    }
    return _webView;
}

加载HTML

- (void)configuration:(NSString *)html{
    if (html.length > 0 && ([html containsString:@"http"] || [html containsString:@"https"])) {
        [self.webView loadHTMLString:html baseURL:nil];
    }
}

禁止缩放

- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView{
    return nil;
}
//监听移除
- (void)removeObserverForWebViewContentSize {
    [_webView.scrollView removeObserver:self forKeyPath:contentSizeKey];
}

//KVO获取高度
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{
    if ([keyPath isEqualToString:contentSizeKey]) {
        CGFloat height = self.webView.scrollView.contentSize.height;
        id old = change[NSKeyValueChangeOldKey];
        id new = change[NSKeyValueChangeNewKey];
//        NSLog(@"height-->%f->old-->%@-->new-->%@",height,old,new);
        if (height > 0) {
            if (_wkWebViewHeight) {
                _webView.frame = CGRectMake(0, 0, ScreenW, height);
                self.indicatorView.center = _webView.center;
                self.wkWebViewHeight(height);
            }
        }
        if ([old isEqual:new]) {
            [self removeObserverForWebViewContentSize];//重点 : 高度回调后把监听移除,不然会重复走这段代码
            self.loadFinished();
        }
    }
}

//当webview加载完成,再次更新高度
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {
    NSLog(@"加载结束didFinishNavigation");
    [self.indicatorView stopAnimating];
    CGFloat webH = webView.scrollView.contentSize.height;
    _webView.frame = CGRectMake(0, 0, ScreenW, webH);
    if (_wkWebViewHeight) {
        self.wkWebViewHeight(webH);
        self.loadFinished();
    }
}

controller里更加获取的高度刷新tableview

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
···
      cell.wkWebViewHeight = ^(CGFloat height) {
            if (weakSelf.webViewH != height) {
                weakSelf.webViewH = height;
                [weakSelf.tableView beginUpdates];
                [weakSelf.tableView endUpdates];
            }
            
        };
        cell.loadFinished = ^{
            [weakSelf.tableView beginUpdates];
            [weakSelf.tableView endUpdates];
        };
···
}

以上仅为本人在开发中遇到的问题,并尝试解决,如有问题,欢迎指正,谢谢!

你可能感兴趣的:(UITableView中加载WKWebView,高度计算问题)