1. ホーム
  2. ios

WKWebViewのコンテンツサイズを決定する方法は?

2023-09-14 11:54:49

質問

iOS 8 およびそれ以降の環境で実行するときに、動的に割り当てられた UIWebView のインスタンスを WKWebView インスタンスに置き換えることを実験していますが、WKWebView のコンテンツ サイズを決定する方法が見当たりません。

私のウェブビューは、より大きな UIScrollView コンテナ内に埋め込まれているので、ウェブビューのための理想的なサイズを決定する必要があります。 これにより、ウェブビュー内でスクロールする必要なく、その HTML コンテンツのすべてを表示するためにそのフレームを変更することができ、スクロールビュー コンテナの正しい高さを設定することができます (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の高さを返します。

どのように解決するのですか?

私はこの主題に関するすべての答えを読んだと思うが、私が持っていたすべては、解決策の一部だった。ほとんどの時間を費やして、@davew によって説明された KVO メソッドを実装しようとしましたが、これは時々動作しましたが、ほとんどの場合、WKWebView コンテナのコンテンツの下に空白が残りました。また、@David Beckの提案で、コンテナの高さを0にすることで、コンテナの高さがコンテンツの高さより大きい場合に問題が発生する可能性を回避しました。にもかかわらず、時折、空白のスペースが発生しました。 というわけで、私にとっては、quot;contentSize" observerには多くの欠点がありました。私はウェブテクノロジーの経験があまりないので、このソリューションの何が問題だったのか答えられませんが、コンソールに高さだけを表示して、それに対して何もしない場合(例えば、制約を変更する)、ある数字(例えば、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 を設定すると、次のステップ( document.body.offsetHeight ) が適切なタイミングで呼び出され、正しい高さの数値が返されます。