異なる(単一ページ)コンテンツのUIWebView
があります。親ビューのサイズを適切に変更するために、コンテンツのCGSize
を見つけたいです。明らかな-sizeThatFits:
は、残念ながらwebViewの現在のフレームサイズを返すだけです。
-sizeThatFits:
を使用した最初の推測は完全に間違っていなかったことが判明しました。動作するようですが、-sizeThatFits:
を送信する前にwebViewのフレームが最小サイズに設定されている場合のみです。その後、フィッティングサイズによって間違ったフレームサイズを修正できます。これはひどいように聞こえますが、実際にはそれほど悪くはありません。両方のフレームを次々に変更するため、ビューは更新されず、ちらつきません。
もちろん、コンテンツが読み込まれるまで待つ必要があるため、コードを-webViewDidFinishLoad:
デリゲートメソッドに配置します。
Obj-C
- (void)webViewDidFinishLoad:(UIWebView *)aWebView {
CGRect frame = aWebView.frame;
frame.size.height = 1;
aWebView.frame = frame;
CGSize fittingSize = [aWebView sizeThatFits:CGSizeZero];
frame.size = fittingSize;
aWebView.frame = frame;
NSLog(@"size: %f, %f", fittingSize.width, fittingSize.height);
}
Swift 4.x
func webViewDidFinishLoad(_ webView: UIWebView) {
var frame = webView.frame
frame.size.height = 1
webView.frame = frame
let fittingSize = webView.sizeThatFits(CGSize.init(width: 0, height: 0))
frame.size = fittingSize
webView.frame = frame
}
JavaScriptを使用する 別のアプローチ (@GregInYEGに感謝)があることを指摘する必要があります。どちらのソリューションのパフォーマンスが良いかわからない。
ハッキーな2つのソリューションのうち、私はこれがより気に入っています。
この質問を復活させるのは、ほとんどの場合にしか機能しないというOrtwinの答えを見つけたからです...
webViewDidFinishLoad
メソッドは複数回呼び出すことができ、sizeThatFits
によって返される最初の値は、最終的なサイズの一部にすぎません。何らかの理由で、sizeThatFits
が再度起動したときにwebViewDidFinishLoad
を次に呼び出すと、以前と同じ値が誤って返されます。これは、ある種の同時実行の問題であるかのように、同じコンテンツに対してランダムに発生します。おそらく、この動作は時間の経過とともに変化したのは、私がiOS 5向けにビルドしており、sizeToFit
がほぼ同じ方法で動作することを発見したためです(以前はそうではなかったのですか?)
私はこの簡単な解決策に落ち着きました:
- (void)webViewDidFinishLoad:(UIWebView *)aWebView
{
CGFloat height = [[aWebView stringByEvaluatingJavaScriptFromString:@"document.height"] floatValue];
CGFloat width = [[aWebView stringByEvaluatingJavaScriptFromString:@"document.width"] floatValue];
CGRect frame = aWebView.frame;
frame.size.height = height;
frame.size.width = width;
aWebView.frame = frame;
}
スイフト(2.2):
func webViewDidFinishLoad(webView: UIWebView) {
if let heightString = webView.stringByEvaluatingJavaScriptFromString("document.height"),
widthString = webView.stringByEvaluatingJavaScriptFromString("document.width"),
height = Float(heightString),
width = Float(widthString) {
var rect = webView.frame
rect.size.height = CGFloat(height)
rect.size.width = CGFloat(width)
webView.frame = rect
}
}
更新:コメントで述べたように、コンテンツが縮小した場合をキャッチしていないようです。すべてのコンテンツとOSバージョンに当てはまるかどうかわからない場合は、試してみてください。
Xcode 8およびiOS 10では、Webビューの高さを決定します。使用して高さを取得できます
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
CGFloat height = [[webView stringByEvaluatingJavaScriptFromString:@"document.body.scrollHeight"] floatValue];
NSLog(@"Webview height is:: %f", height);
}
SwiftのOR
func webViewDidFinishLoad(aWebView:UIWebView){
let height: Float = (aWebView.stringByEvaluatingJavaScriptFromString("document.body.scrollHeight")?.toFloat())!
print("Webview height is::\(height)")
}
単純な解決策はwebView.scrollView.contentSize
を使用することですが、これがJavaScriptで機能するかどうかはわかりません。 JavaScriptが使用されていない場合、これは確実に機能します。
- (void)webViewDidFinishLoad:(UIWebView *)aWebView {
CGSize contentSize = aWebView.scrollView.contentSize;
NSLog(@"webView contentSize: %@", NSStringFromCGSize(contentSize));
}
これは変です!
sizeThatFits:
と[webView stringByEvaluatingJavaScriptFromString:@"document.body.scrollHeight"]
の両方のソリューションをテストしましたではなく私のために働いています。
しかし、ウェブページのコンテンツの適切な高さを取得するための興味深い簡単な方法を見つけました。現在、私はデリゲートメソッドscrollViewDidScroll:
でそれを使用しました。
CGFloat contentHeight = scrollView.contentSize.height - CGRectGetHeight(scrollView.frame);
IOS 9.3シミュレータ/デバイスで検証済み、幸運を祈ります!
編集:
背景:htmlコンテンツは、文字列変数とHTTPコンテンツテンプレートによって計算され、メソッドloadHTMLString:baseURL:
によってロードされ、そこに登録されたJSスクリプトはありません。
IOS10では、document.height
の値が0(ゼロ)だったので、document.body.scrollHeight
はWebviewでドキュメントの高さを取得するためのソリューションです。この問題は、width
についても解決できます。
[webView sizeThatFits:CGSizeZero]
を使用して、コンテンツのサイズを把握できます。
Scrollviewのどこかでサブビューとしてwebviewを使用する場合、高さの制約を一定の値に設定し、後でそこからアウトレットを作成し、次のように使用できます。
- (void)webViewDidFinishLoad:(UIWebView *)webView {
webView.scrollView.scrollEnabled = NO;
_webViewHeight.constant = webView.scrollView.contentSize.height;
}
ここでの提案はどれも私の状況を助けてくれませんでしたが、答えが得られたものを読みました。 UIWebViewが続くUIコントロールの固定セットを持つViewControllerがあります。 UIコントロールがHTMLコンテンツに接続されているかのようにページ全体をスクロールしたかったため、UIWebViewでスクロールを無効にし、親スクロールビューのコンテンツサイズを正しく設定する必要があります。
重要なヒントは、UIWebViewは画面にレンダリングされるまでそのサイズを正しく報告しないことでした。そのため、コンテンツを読み込むときに、コンテンツサイズを利用可能な画面の高さに設定します。次に、viewDidAppearで、スクロールビューのコンテンツサイズを正しい値に更新します。ローカルコンテンツでloadHTMLStringを呼び出しているため、これはうまくいきました。 loadRequestを使用している場合、htmlの取得速度に応じて、webViewDidFinishLoadのcontentSizeも更新する必要があります。
スクロールビューの非表示部分のみが変更されるため、ちらつきはありません。
サブビューではない(したがってウィンドウ階層の一部ではない)UIWebView
を使用して、UITableViewCells
のHTMLコンテンツのサイズを決定しています。切断されたUIWebView
は、-[UIWebView sizeThatFits:]
でそのサイズを適切に報告しないことがわかりました。さらに、 https://stackoverflow.com/a/3937599/9636 で説明されているように、UIWebView
のframe
height
を1に設定して、まったく適切な高さを取得します。
UIWebView
の高さが大きすぎる場合(つまり、1000に設定しているが、HTMLコンテンツのサイズは500のみ):
UIWebView.scrollView.contentSize.height
-[UIWebView stringByEvaluatingJavaScriptFromString:@"document.height"]
-[UIWebView sizeThatFits:]
すべてが1000のheight
を返します。
この場合の問題を解決するために、私は https://stackoverflow.com/a/11770883/9636 を使用しました。ただし、UIWebView.frame.width
が-[UIWebView sizeThatFits:]
width
と同じ場合にのみ、このソリューションを使用します。
HTMLにheavyiframeのようなHTMLコンテンツ(つまり、facebook-、Twitter、instagram-embeds)が含まれる場合、実際のソリューションははるかに困難です。最初にHTMLをラップします。
[htmlContent appendFormat:@"<html>", [[LocalizationStore instance] currentTextDir], [[LocalizationStore instance] currentLang]];
[htmlContent appendFormat:@"<head>"];
[htmlContent appendString:@"<script type=\"text/javascript\">"];
[htmlContent appendFormat:@" var lastHeight = 0;"];
[htmlContent appendFormat:@" function updateHeight() { var h = document.getElementById('content').offsetHeight; if (lastHeight != h) { lastHeight = h; window.location.href = \"x-update-webview-height://\" + h } }"];
[htmlContent appendFormat:@" window.onload = function() {"];
[htmlContent appendFormat:@" setTimeout(updateHeight, 1000);"];
[htmlContent appendFormat:@" setTimeout(updateHeight, 3000);"];
[htmlContent appendFormat:@" if (window.intervalId) { clearInterval(window.intervalId); }"];
[htmlContent appendFormat:@" window.intervalId = setInterval(updateHeight, 5000);"];
[htmlContent appendFormat:@" setTimeout(function(){ clearInterval(window.intervalId); window.intervalId = null; }, 30000);"];
[htmlContent appendFormat:@" };"];
[htmlContent appendFormat:@"</script>"];
[htmlContent appendFormat:@"..."]; // Rest of your HTML <head>-section
[htmlContent appendFormat:@"</head>"];
[htmlContent appendFormat:@"<body>"];
[htmlContent appendFormat:@"<div id=\"content\">"]; // !important https://stackoverflow.com/a/8031442/1046909
[htmlContent appendFormat:@"..."]; // Your HTML-content
[htmlContent appendFormat:@"</div>"]; // </div id="content">
[htmlContent appendFormat:@"</body>"];
[htmlContent appendFormat:@"</html>"];
次に、shouldStartLoadWithRequestに処理x-update-webview-height-schemeを追加します。
if (navigationType == UIWebViewNavigationTypeLinkClicked || navigationType == UIWebViewNavigationTypeOther) {
// Handling Custom URL Scheme
if([[[request URL] scheme] isEqualToString:@"x-update-webview-height"]) {
NSInteger currentWebViewHeight = [[[request URL] Host] intValue];
if (_lastWebViewHeight != currentWebViewHeight) {
_lastWebViewHeight = currentWebViewHeight; // class property
_realWebViewHeight = currentWebViewHeight; // class property
[self layoutSubviews];
}
return NO;
}
...
最後に、layoutSubviews内に次のコードを追加します。
...
NSInteger webViewHeight = 0;
if (_realWebViewHeight > 0) {
webViewHeight = _realWebViewHeight;
_realWebViewHeight = 0;
} else {
webViewHeight = [[webView stringByEvaluatingJavaScriptFromString:@"document.getElementById(\"content\").offsetHeight;"] integerValue];
}
upateWebViewHeightTheWayYorLike(webViewHeight);// Now your have real WebViewHeight so you can update your webview height you like.
...
追伸ObjectiveC/Swift-code内に時間遅延(SetTimeoutおよびsetInterval)を実装できます-それはあなた次第です。
追伸UIWebViewおよびFacebook埋め込みに関する重要な情報: 埋め込みFacebook投稿はUIWebViewで適切に表示されません
私もこの問題にこだわっており、webViewの動的な高さを計算したい場合は、最初にwebViewの幅を伝える必要があることに気づいたので、jsの前に1行を追加すると、非常に正確な実際の高さ。
コードは次のように簡単です。
-(void)webViewDidFinishLoad:(UIWebView *)webView
{
//tell the width first
webView.width = [UIScreen mainScreen].bounds.size.width;
//use js to get height dynamically
CGFloat scrollSizeHeight = [[webView stringByEvaluatingJavaScriptFromString:@"document.body.scrollHeight"] floatValue];
webView.height = scrollSizeHeight;
webView.x = 0;
webView.y = 0;
//......
}
Xcode8 Swift3.1:
webViewDidFinishLoad
デリゲート:let height = webView.scrollView.contentSize.height
ステップ1がなければ、webview.height>実際のcontentHeightの場合、ステップ2はwebview.heightを返しますが、contentsize.heightは返しません。
また、iOS 7では、前述のすべてのメソッドが適切に機能するように、View Controller viewDidLoad
メソッドにこれを追加します。
if ([self respondsToSelector:@selector(automaticallyAdjustsScrollViewInsets)]) {
self.automaticallyAdjustsScrollViewInsets = NO;
}
そうしないと、どちらのメソッドも正常に機能しません。