77

我正在尝试在 iOS 8 及更高版本下运行时用 WKWebView 实例替换动态分配的 UIWebView 实例,但我找不到确定 WKWebView 内容大小的方法。

我的 Web 视图嵌入在更大的 UIScrollView 容器中,因此我需要确定 Web 视图的理想大小。这将允许我修改其框架以显示其所有 HTML 内容,而无需在 Web 视图中滚动,并且我将能够为滚动视图容器设置正确的高度(通过设置 scrollview.contentSize)。

我试过 sizeToFit 和 sizeThatFits 都没有成功。这是我创建 WKWebView 实例并将其添加到容器滚动视图的代码:

// self.view is a UIScrollView sized to something like 320.0 x 400.0.
CGRect wvFrame = CGRectMake(0, 0, self.view.frame.size.width, 100.0);
self.mWebView = [[[WKWebView alloc] initWithFrame:wvFrame] autorelease];
self.mWebView.navigationDelegate = self;
self.mWebView.scrollView.bounces = NO;
self.mWebView.scrollView.scrollEnabled = NO;

NSString *s = ... // Load s from a Core Data field.
[self.mWebView loadHTMLString:s baseURL:nil];

[self.view addSubview:self.mWebView];

这是一个实验性的 didFinishNavigation 方法:

- (void)webView:(WKWebView *)aWebView
                             didFinishNavigation:(WKNavigation *)aNavigation
{
    CGRect wvFrame = aWebView.frame;
    NSLog(@"original wvFrame: %@\n", NSStringFromCGRect(wvFrame));
    [aWebView sizeToFit];
    NSLog(@"wvFrame after sizeToFit: %@\n", NSStringFromCGRect(wvFrame));
    wvFrame.size.height = 1.0;
    aWebView.frame = wvFrame;
    CGSize sz = [aWebView sizeThatFits:CGSizeZero];
    NSLog(@"sizeThatFits A: %@\n", NSStringFromCGSize(sz));
    sz = CGSizeMake(wvFrame.size.width, 0.0);
    sz = [aWebView sizeThatFits:sz];
    NSLog(@"sizeThatFits B: %@\n", NSStringFromCGSize(sz));
}

这是生成的输出:

2014-12-16 17:29:38.055 App[...] original wvFrame: {{0, 0}, {320, 100}}
2014-12-16 17:29:38.055 App[...] wvFrame after sizeToFit: {{0, 0}, {320, 100}}
2014-12-16 17:29:38.056 App[...] wvFrame after sizeThatFits A: {320, 1}
2014-12-16 17:29:38.056 App[...] wvFrame after sizeThatFits B: {320, 1}

sizeToFit 调用无效,并且 sizeThatFits 始终返回高度 1。

4

18 回答 18

131

我想我阅读了有关此主题的所有答案,而我所拥有的只是解决方案的一部分。大部分时间我都在尝试实现@davew 所描述的 KVO 方法,它偶尔会起作用,但大部分时间在 WKWebView 容器的内容下留下了一个空白。我还实现了@David Beck 的建议,并将容器高度设为 0,从而避免了容器高度大于内容高度时出现问题的可能性。尽管如此,我还是有偶尔的空白。所以,对我来说,“contentSize”观察者有很多缺陷。我没有太多的网络技术经验,所以我无法回答这个解决方案有什么问题,但我看到如果我只在控制台中打印高度但不做任何事情(例如调整约束),它跳到某个数字(例如 5000),然后转到最高数字之前的数字(例如 2500 - 结果是正确的数字)。如果我确实将高度约束设置为我从“contentSize”获得的高度,它会将自己设置为它获得的最高数字,并且永远不会调整为正确的数字 - 这也是@David Beck 评论提到的。

经过大量实验,我设法找到了适合我的解决方案:

func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
    self.webView.evaluateJavaScript("document.readyState", completionHandler: { (complete, error) in
        if complete != nil {
            self.webView.evaluateJavaScript("document.body.scrollHeight", completionHandler: { (height, error) in
                self.containerHeight.constant = height as! CGFloat
            })
        }

        })
}

当然,重要的是要正确设置约束,以便 scrollView 根据 containerHeight 约束调整大小。

事实证明,didFinish 导航方法永远不会在我想要的时候被调用,但是在设置document.readyState了 step 之后,下一个 ( document.body.offsetHeight) 会在正确的时刻被调用,并返回正确的高度数字。

于 2017-08-14T12:29:06.190 回答
29

您可以使用键值观察(KVO)...

在您的视图控制器中:

- (void)viewDidLoad {
    ...
    [self.webView.scrollView addObserver:self forKeyPath:@"contentSize" options:NSKeyValueObservingOptionNew context:nil];
}


- (void)dealloc
{
    [self.webView.scrollView removeObserver:self forKeyPath:@"contentSize" context:nil];
}


- (void)observeValueForKeyPath:(NSString *)keyPath
                      ofObject:(id)object
                        change:(NSDictionary *)change
                       context:(void *)context
{
    if (object == self.webView.scrollView && [keyPath isEqual:@"contentSize"]) {
        // we are here because the contentSize of the WebView's scrollview changed.

        UIScrollView *scrollView = self.webView.scrollView;
        NSLog(@"New contentSize: %f x %f", scrollView.contentSize.width, scrollView.contentSize.height);
    }
}

这将节省 JavaScript 的使用并让您随时了解所有更改。

于 2015-10-28T18:10:25.310 回答
19

我最近不得不自己处理这个问题。最后,我使用了Chris McClenaghan 提出的解决方案的修改。

实际上,他的原始解决方案非常好,并且适用于大多数简单的情况。但是,它只适用于带有文本的页面。它可能也适用于具有静态高度的图像的页面。max-height但是,当您拥有使用和max-width属性定义大小的图像时,它肯定不起作用。

这是因为这些元素可以在页面加载后调整大小。所以,实际上,返回的高度onLoad总是正确的。但它只对那个特定的实例是正确的。解决方法是监视body高度的变化并做出响应。

监视器调整大小document.body

var shouldListenToResizeNotification = false
lazy var webView:WKWebView = {
    //Javascript string
    let source = "window.onload=function () {window.webkit.messageHandlers.sizeNotification.postMessage({justLoaded:true,height: document.body.scrollHeight});};"
    let source2 = "document.body.addEventListener( 'resize', incrementCounter); function incrementCounter() {window.webkit.messageHandlers.sizeNotification.postMessage({height: document.body.scrollHeight});};"
    
    //UserScript object
    let script = WKUserScript(source: source, injectionTime: .atDocumentEnd, forMainFrameOnly: true)
    
    let script2 = WKUserScript(source: source2, injectionTime: .atDocumentEnd, forMainFrameOnly: true)
    
    //Content Controller object
    let controller = WKUserContentController()
    
    //Add script to controller
    controller.addUserScript(script)
    controller.addUserScript(script2)
    
    //Add message handler reference
    controller.add(self, name: "sizeNotification")
    
    //Create configuration
    let configuration = WKWebViewConfiguration()
    configuration.userContentController = controller
    
    return WKWebView(frame: CGRect.zero, configuration: configuration)
}()

func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
    guard let responseDict = message.body as? [String:Any],
    let height = responseDict["height"] as? Float else {return}
    if self.webViewHeightConstraint.constant != CGFloat(height) {
        if let _ = responseDict["justLoaded"] {
            print("just loaded")
            shouldListenToResizeNotification = true
            self.webViewHeightConstraint.constant = CGFloat(height)
        }
        else if shouldListenToResizeNotification {
            print("height is \(height)")
            self.webViewHeightConstraint.constant = CGFloat(height)
        }
        
    }
}

这个解决方案是迄今为止我能想到的最优雅的解决方案。但是,您应该注意两件事。

首先,在加载您的 URL 之前,您应该设置shouldListenToResizeNotificationfalse. 当加载的 URL 可以快速更改时,需要这种额外的逻辑。发生这种情况时,由于某种原因,来自旧内容的通知可能会与来自新内容的通知重叠。为了防止这种行为,我创建了这个变量。它确保一旦我们开始加载新内容,我们将不再处理来自旧内容的通知,并且我们只会在加载新内容后恢复处理调整大小通知。

然而,最重要的是,您需要注意这一点:

如果您采用此解决方案,您需要考虑到,如果您将您的尺寸更改为WKWebView通知报告的尺寸以外的任何尺寸 - 将再次触发通知。

请注意这一点,因为它很容易进入无限循环。例如,如果您决定通过使您的高度等于报告的高度 + 一些额外的填充来处理通知:

func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
        guard let responseDict = message.body as? [String:Float],
        let height = responseDict["height"] else {return}
        self.webViewHeightConstraint.constant = CGFloat(height+8)
    }

如您所见,因为我在报告的高度上加了 8,所以完成后我的尺寸body会发生变化,并且会再次发布通知。

警惕这种情况,否则你应该没事。

如果您发现此解决方案有任何问题,请告诉我 - 我自己依赖它,所以最好知道是否有一些我没有发现的错误!

于 2017-01-06T17:51:38.640 回答
11

为我工作

extension TransactionDetailViewController: WKNavigationDelegate {
    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
            self.webviewHeightConstraint.constant = webView.scrollView.contentSize.height
        }
    }
}
于 2018-12-18T07:48:35.443 回答
7

试试下面的。无论您在哪里实例化 WKWebView 实例,都添加类似于以下内容的内容:

    //Javascript string
    NSString * source = @"window.webkit.messageHandlers.sizeNotification.postMessage({width: document.width, height: document.height});";

    //UserScript object
    WKUserScript * script = [[WKUserScript alloc] initWithSource:source injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:YES];

    //Content Controller object
    WKUserContentController * controller = [[WKUserContentController alloc] init];

    //Add script to controller
    [controller addUserScript:script];

    //Add message handler reference
    [controller addScriptMessageHandler:self name:@"sizeNotification"];

    //Create configuration
    WKWebViewConfiguration * configuration = [[WKWebViewConfiguration alloc] init];

    //Add controller to configuration
    configuration.userContentController = controller;

    //Use whatever you require for WKWebView frame
    CGRect frame = CGRectMake(...?);

    //Create your WKWebView instance with the configuration
    WKWebView * webView = [[WKWebView alloc] initWithFrame:frame configuration:configuration];

    //Assign delegate if necessary
    webView.navigationDelegate = self;

    //Load html
    [webView loadHTMLString:@"some html ..." baseURL:[[NSBundle mainBundle] bundleURL]];

然后添加一个类似于以下的方法,该类遵循 WKScriptMessageHandler 协议来处理消息:

- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
    CGRect frame = message.webView.frame;
    frame.size.height = [[message.body valueForKey:@"height"] floatValue];
    message.webView.frame = frame;}

这对我有用。

如果您的文档中有多个文本,则可能需要像这样包装 javascript 以确保所有内容都已加载:

@"window.onload=function () { window.webkit.messageHandlers.sizeNotification.postMessage({width: document.width, height: document.height});};"

注意:此解决方案不解决对文档的持续更新。

于 2015-01-27T22:05:15.150 回答
7

您还可以通过 evaluateJavaScript 获得 WKWebView 的内容高度。

- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {
    [webView evaluateJavaScript:@"Math.max(document.body.scrollHeight, document.body.offsetHeight, document.documentElement.clientHeight, document.documentElement.scrollHeight, document.documentElement.offsetHeight)"
              completionHandler:^(id _Nullable result, NSError * _Nullable error) {
                  if (!error) {
                      CGFloat height = [result floatValue];
                      // do with the height

                  }
              }];
}
于 2019-01-18T09:14:27.957 回答
6

您需要等待 webview 完成加载。这是我使用的一个工作示例

WKWebView 内容加载函数永远不会被调用

然后在 webview 完成加载后,您可以通过

func webView(webView: WKWebView!, didFinishNavigation navigation: WKNavigation!) {

   println(webView.scrollView.contentSize.height)

}
于 2014-12-17T19:07:54.167 回答
6

大多数答案都使用“document.body.offsetHeight”。

这隐藏了身体的最后一个对象。

我通过使用 KVO 观察者来监听 WKWebview “contentSize”中的变化,然后运行以下代码,从而克服了这个问题:

self.webView.evaluateJavaScript(
    "(function() {var i = 1, result = 0; while(true){result = 
    document.body.children[document.body.children.length - i].offsetTop + 
    document.body.children[document.body.children.length - i].offsetHeight;
    if (result > 0) return result; i++}})()",
    completionHandler: { (height, error) in
        let height = height as! CGFloat
        self.webViewHeightConstraint.constant = height
    }
)

这不是最漂亮的代码,但它对我有用。

于 2018-02-24T22:11:51.033 回答
5

我发现 hlung here 的答案,如下扩展 WKWebView 对我来说是最简单和最有效的解决方案:

https://gist.github.com/pkuecuekyan/f70096218a6b969e0249427a7d324f91

他的评论如下:

“太好了!对我来说,我没有设置 webView.frame,而是设置了 autolayout intrinsicContentSize。”

他的代码如下:

import UIKit
import WebKit

class ArticleWebView: WKWebView {

  init(frame: CGRect) {
    let configuration = WKWebViewConfiguration()
    super.init(frame: frame, configuration: configuration)
    self.navigationDelegate = self
  }

  required init?(coder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
  }

  override var intrinsicContentSize: CGSize {
    return self.scrollView.contentSize
  }

}

extension ArticleWebView: WKNavigationDelegate {

  func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
    webView.evaluateJavaScript("document.readyState", completionHandler: { (_, _) in
      webView.invalidateIntrinsicContentSize()
    })
  }

}
于 2019-11-11T17:18:19.713 回答
3

这是对@IvanMih 答案的轻微编辑。对于那些在您的解决方案结束时遇到大空白区域的人来说,WKWebview这个解决方案对我来说效果很好:

func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
  webView.evaluateJavaScript("document.readyState", completionHandler: { (complete, error) in

    if complete != nil {
      let height = webView.scrollView.contentSize
      print("height of webView is: \(height)")
    }
  })
}

所以基本上不是根据scrollHeight您使用计算高度来计算高度webView.scrollView.contentSize。我确信在某些情况下这会中断,但我认为它对于静态内容会做得很好,并且如果您在无需用户滚动的情况下显示所有内容。

于 2019-06-06T20:25:40.110 回答
3

经过大量实验后,我设法找到了一个适合我的解决方案样式为 HTML 并使用字体大小和高度

Swift 中的代码

1-给你的 Webview 导航委托

  webView.navigationDelegate = self

2-在代表团扩展

extension yourclass : WKNavigationDelegate {
      func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
        // Handel Dynamic Height For Webview Loads with HTML
       // Most important to reset webview height to any desired height i prefer 1 or 0  
        webView.frame.size.height = 1
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
        // here get height constant and assign new height in it 
            if let constraint = (webView.constraints.filter{$0.firstAttribute == .height}.first) {
                constraint.constant = webView.scrollView.contentSize.height
            }
 }

希望它也适用于你们

于 2019-07-03T20:24:24.290 回答
2

使用@Andriy 的答案和这个答案,我能够在 WKWebView 中设置获取 contentSize 的高度并更改它的高度。

这是完整的 swift 4 代码:

    var neededConstraints: [NSLayoutConstraint] = []

    @IBOutlet weak var webViewContainer: UIView!
    @IBOutlet weak var webViewHeight: NSLayoutConstraint! {
        didSet {
            if oldValue != nil, oldValue.constant != webViewHeight.constant {
                view.layoutIfNeeded()
            }
        }
    }


   lazy var webView: WKWebView = {
        var source = """
var observeDOM = (function(){
    var MutationObserver = window.MutationObserver || window.WebKitMutationObserver,
        eventListenerSupported = window.addEventListener;

    return function(obj, callback){
        if( MutationObserver ){
            // define a new observer
            var obs = new MutationObserver(function(mutations, observer){
                if( mutations[0].addedNodes.length || mutations[0].removedNodes.length )
                    callback();
            });
            // have the observer observe foo for changes in children
            obs.observe( obj, { childList:true, subtree:true });
        }
        else if( eventListenerSupported ){
            obj.addEventListener('DOMNodeInserted', callback, false);
            obj.addEventListener('DOMNodeRemoved', callback, false);
        }
    };
})();

// Observe a specific DOM element:
observeDOM( document.body ,function(){
    window.webkit.messageHandlers.sizeNotification.postMessage({'scrollHeight': document.body.scrollHeight,'offsetHeight':document.body.offsetHeight,'clientHeight':document.body.clientHeight});
});

"""

        let script = WKUserScript(source: source, injectionTime: .atDocumentEnd, forMainFrameOnly: true)
        let controller = WKUserContentController()
        controller.addUserScript(script)
        controller.add(self, name: "sizeNotification")
        let configuration = WKWebViewConfiguration()
        configuration.userContentController = controller
        let this = WKWebView(frame: .zero, configuration: configuration)
        webViewContainer.addSubview(this)
        this.translatesAutoresizingMaskIntoConstraints = false
        this.scrollView.isScrollEnabled = false
        // constraint for webview when added to it's superview
        neededConstraints += NSLayoutConstraint.constraints(withVisualFormat: "H:|[web]|",
                                                            options: [],
                                                            metrics: nil,
                                                            views: ["web": this])
        neededConstraints += NSLayoutConstraint.constraints(withVisualFormat: "V:|[web]|",
                                                            options: [],
                                                            metrics: nil,
                                                            views: ["web": this])
        return this
    }()


    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        _  = webView // to create constraints needed for webView
        NSLayoutConstraint.activate(neededConstraints)
        let url = URL(string: "https://www.awwwards.com/")!
        let request = URLRequest(url: url)
        webView.load(request)
    }

    func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
        if let body = message.body as? Dictionary<String, CGFloat>,
            let scrollHeight = body["scrollHeight"],
            let offsetHeight = body["offsetHeight"],
            let clientHeight = body["clientHeight"] {
            webViewHeight.constant = scrollHeight
            print(scrollHeight, offsetHeight, clientHeight)
        }
    }
于 2017-10-23T13:51:04.720 回答
2

我在 UITableViewCell 中尝试了 Javascript 版本,它运行良好。但是,如果你想把它放在滚动视图中。我不知道为什么,高度可以更高,但不能更短。但是,我在这里找到了 UIWebView 解决方案。https://stackoverflow.com/a/48887971/5514452

它也适用于 WKWebView。我认为问题是因为 WebView 需要重新布局,但不知何故它不会缩小,只能放大。我们需要重置高度,它肯定会调整大小。

编辑:我在设置约束后重置了框架高度,因为有时由于将框架高度设置为 0 它将无法工作。

func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
    self.webView.frame.size.height = 0
    self.webView.evaluateJavaScript("document.readyState", completionHandler: { (complete, error) in
        if complete != nil {
            self.webView.evaluateJavaScript("document.body.scrollHeight", completionHandler: { (height, error) in
                let webViewHeight = height as! CGFloat
                self.webViewHeightConstraint.constant = webViewHeight
                self.webView.frame.size.height = webViewHeight
            })
        }
    })
}
于 2018-08-24T02:55:33.823 回答
1

我已经尝试过滚动视图 KVO,并且尝试过评估文档上的 javascript,使用clientHeight,offsetHeight等...

最终对我有用的是:document.body.scrollHeight. 或使用scrollHeight最顶层元素的 ,例如 container div

loading使用 KVO 监听 WKWebview 属性更改:

[webview addObserver: self forKeyPath: NSStringFromSelector(@selector(loading)) options: NSKeyValueObservingOptionNew context: nil];

进而:

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
    if(object == self.webview && [keyPath isEqualToString: NSStringFromSelector(@selector(loading))]) {
        NSNumber *newValue = change[NSKeyValueChangeNewKey];
        if(![newValue boolValue]) {
            [self updateWebviewFrame];
        }
    }
}

updateWebviewFrame实施:

[self.webview evaluateJavaScript: @"document.body.scrollHeight" completionHandler: ^(id response, NSError *error) {
     CGRect frame = self.webview.frame;
     frame.size.height = [response floatValue];
     self.webview.frame = frame;
}];
于 2016-12-25T13:49:01.247 回答
1

也尝试了不同的方法,最终得出了一个解决方案。结果,我制作了一个自调整大小的 WKWebView,它使它的intrinsicContentSize适应其内容的大小。所以你可以在Auto Layouts中使用它。作为一个例子,我做了一个视图,它可以帮助你在 iOS 应用程序上显示数学公式:https ://github.com/Mazorati/SVLatexView

于 2019-07-15T22:06:43.187 回答
0

以下代码对我来说非常适合 webkit 中的任何内容。确保将以下委托添加到您的类:WKNavigationDelegate。

func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
        self.bodyWebView.evaluateJavaScript("document.readyState", completionHandler: { (complete, error) in
            if complete != nil {
                self.bodyWebView.evaluateJavaScript("document.body.scrollHeight", completionHandler: { (height, error) in
                    let heightWebView = height as! CGFloat
                    //heightWebView is the height of the web view
                })
            }
        })
    }
}

调度很重要,因为这样可以确保在加载 web 视图结束时获得的高度是正确的,这是由于 html 可能具有的元素类型而发生的。

于 2020-04-14T19:26:16.617 回答
0

我想为上述答案中未提及的特殊情况提供解决方案,如果您在 WKWebView 中使用自定义字体,可能会发生这种情况。

我尝试了此处解释的所有解决方案,以及其他 StackOverflow 问题中提到的许多其他解决方案。没有什么对我来说是 100% 正确的。我总是遇到同样的问题:返回的高度总是比WkWebView 的实际高度小一点。我尝试了 WKNavigationDelegate 的方式,并尝试通过将 js 注入呈现的 HTML 中来监听自生成的事件,但没有成功,在所有情况下高度总是错误的。

我学到的第一件事是:在加载 html 并等待完成事件之前,必须将 webview 添加到布局中。如果您尝试以孤立的方式渲染 webview 而不将其添加到布局中,那么高度将非常错误。

奇怪的是,我发现在html渲染后设置断点,在调用高度评估方法之前,返回的高度是正确的。测量哪个高度(scrollHeight 或 offsetheight)并不重要,两者总是正确的。

这为我指明了正确的方向。结论很明显(虽然我花了很多天调试才意识到):收到didFinishNavigation事件后,或者如果你使用自定义js并监听window.onload事件或类似事件,返回的高度几乎是正确的但不完全是因为渲染还没有完成。

正如这里所解释的,Firefox、Chrome 和 Safari 在 font-face 应用于文档之前触发 DomContenLoaded 事件(也许,在 css 也应用于文档之前?)。就我而言,我使用的是嵌入在我的应用程序中的自定义字体,并以经典方式在 HTML 中引用:

 <style>
    @font-face {
        font-family: 'CustomFont';
        src: url('montserrat.ttf');
        format('truetype');
    }

    body{
        font-family: 'CustomFont';
        font-size: 12px;
    }

解决方案?您必须收听事件 document.fonts.ready,该事件发生在事件 window.onload等之后。在 WkWebView 中加载的 html 中嵌入以下 js:

    document.fonts.ready.then(function() {
 window.webkit.messageHandlers.iosEventListener.postMessage('custom_event_fonts_ready');
  
});

然后在您的 iOS 应用程序中,使用

  self.webView.configuration.userContentController.add(self, name: "iosEventListener")

当收到

        public func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
            if let body = message.body as? String {
                if (body == "custom_event_fonts_ready") {
                        self.evaluateBodyHeight()
    }
            }
        }

 private func evaluateBodyHeight() {
        self.webView.evaluateJavaScript("document.readyState", completionHandler: { (complete, error) in
            if complete != nil {
                self.webView.evaluateJavaScript("document.body.scrollHeight", completionHandler: { (height, error) in
                    let webViewHeight = height as! CGFloat
//Do something with the height.


                })

            }
        })

    }

我不确定,但我认为使用此解决方案,所有测量 web 视图高度的不同方法都将返回正确的方法。经过将近一个月的调试和绝望,我不想测试它们

为我糟糕的英语道歉。

于 2021-07-16T08:31:11.050 回答
0

最好的方法是观察webView.scrollView 的contentSize属性并相应地更新 webView 的高度约束

private var contentSizeObserver: NSKeyValueObservation?
    
contentSizeObserver = webView.scrollView.observe(\.contentSize, options: .new) { [weak self] _, change in
    guard let contentSize = change.newValue else { return }
    self?.csWebViewHeight?.update(offset: contentSize.height)
}

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
    super.viewWillTransition(to: size, with: coordinator)
    // Recalculate webView size
    csWebViewHeight?.update(offset: 0)
    webView.setNeedsLayout()
    webView.layoutIfNeeded()
}
于 2021-11-15T19:35:27.010 回答