J'ai un UIWebView
avec un contenu différent (une seule page). J'aimerais connaître le CGSize
du contenu pour redimensionner correctement les vues de mes parents. L'évident -sizeThatFits:
_ ne renvoie malheureusement que la taille d'image actuelle de la WebView.
Il s’est avéré que ma première hypothèse utilisant -sizeThatFits:
n'était pas complètement faux. Cela semble fonctionner, mais seulement si le cadre de la webView est défini à une taille minimale avant l'envoi -sizeThatFits:
. Après cela, nous pouvons corriger la taille de trame incorrecte par la taille de raccord. Cela semble terrible, mais ce n'est pas si grave. Comme nous modifions les images l'une après l'autre, la vue n'est pas mise à jour et ne scintille pas.
Bien sûr, nous devons attendre que le contenu ait été chargé pour placer le code dans le -webViewDidFinishLoad:
méthode déléguée.
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
}
Je devrais signaler qu'il y a ne autre approche (merci @GregInYEG) en utilisant JavaScript. Vous ne savez pas quelle solution fonctionne le mieux.
De deux solutions de hacky, je préfère celle-ci.
J'ai une autre solution qui fonctionne très bien.
D'une part, l'approche et la solution d'Ortwin fonctionnent uniquement avec iOS 6.0 et versions ultérieures, mais ne fonctionnent pas correctement sous iOS 5.0, 5.1 et 5.1.1, et d'autre part, il y a quelque chose que je n'aime pas et ne comprend pas. avec l'approche d'Ortwin, c'est l'utilisation de la méthode [webView sizeThatFits:CGSizeZero]
avec le paramètre CGSizeZero
: Si vous lisez Apple Documentation officielle sur cette méthode et son paramètre, cela dit clairement:
L’implémentation par défaut de cette méthode renvoie la partie taille du rectangle aux limites de la vue. Les sous-classes peuvent remplacer cette méthode pour renvoyer une valeur personnalisée en fonction de la présentation souhaitée de toutes les sous-vues. Par exemple, un objet UISwitch renvoie une valeur de taille fixe qui représente la taille standard d'une vue de commutateur et un objet UIImageView renvoie la taille de l'image qu'il affiche actuellement.
Ce que je veux dire, c'est que c'est comme s'il avait trouvé sa solution sans aucune logique, car en lisant la documentation, le paramètre passé à [webView sizeThatFits: ...]
Devrait au moins avoir le width
souhaité. Avec sa solution, la largeur souhaitée est définie sur le cadre de webView
avant d'appeler sizeThatFits
avec un paramètre CGSizeZero
. Je maintiens donc que cette solution fonctionne sur iOS 6 par "hasard".
J'ai imaginé une approche plus rationnelle, qui présente l'avantage de fonctionner pour iOS 5.0 et les versions ultérieures ... Et aussi dans des situations complexes où plusieurs vues Web (avec sa propriété webView.scrollView.scrollEnabled = NO
Sont intégrées dans un scrollView
.
Voici mon code pour forcer la présentation du webView
sur le width
souhaité et obtenir le réglage correspondant height
sur le webView
lui-même:
Obj-C
- (void)webViewDidFinishLoad:(UIWebView *)aWebView
{
aWebView.scrollView.scrollEnabled = NO; // Property available in iOS 5.0 and later
CGRect frame = aWebView.frame;
frame.size.width = 200; // Your desired width here.
frame.size.height = 1; // Set the height to a small one.
aWebView.frame = frame; // Set webView's Frame, forcing the Layout of its embedded scrollView with current Frame's constraints (Width set above).
frame.size.height = aWebView.scrollView.contentSize.height; // Get the corresponding height from the webView's embedded scrollView.
aWebView.frame = frame; // Set the scrollView contentHeight back to the frame itself.
}
Swift 4.x
func webViewDidFinishLoad(_ aWebView: UIWebView) {
aWebView.scrollView.isScrollEnabled = false
var frame = aWebView.frame
frame.size.width = 200
frame.size.height = 1
aWebView.frame = frame
frame.size.height = aWebView.scrollView.contentSize.height
aWebView.frame = frame;
}
Notez que dans mon exemple, le webView
était incorporé dans une scrollView
personnalisée ayant un autre webViews
... Tous ces webViews
avaient leur webView.scrollView.scrollEnabled = NO
, et le dernier morceau de code que j’ai dû ajouter était le calcul du height
du contentSize
de mon client scrollView
incorporant ces webViews
, mais c'était aussi facile que de résumer mes frame.size.height
de webView
calculés avec le truc décrit ci-dessus ...
Ressusciter cette question parce que je trouvais que la réponse d'Ortwin ne fonctionnait que la plupart du temps ...
La méthode webViewDidFinishLoad
peut être appelée plusieurs fois, et la première valeur renvoyée par sizeThatFits
ne représente qu'une partie de ce que devrait être la taille finale. Alors pour quelque raison que ce soit, le prochain appel à sizeThatFits
lorsque webViewDidFinishLoad
se déclenchera à nouveau renverra de manière incorrecte la même valeur qu’avant! Cela se produira de manière aléatoire pour le même contenu, comme s'il s'agissait d'un problème de concurrence. Peut-être que ce comportement a changé avec le temps, parce que je construis pour iOS 5 et que j’ai également constaté que sizeToFit
fonctionnait sensiblement de la même manière (bien que cela n’ait pas été le cas auparavant?)
J'ai opté pour cette solution simple:
- (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;
}
Swift (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
}
}
Mise à jour: j'ai constaté, comme indiqué dans les commentaires, que le contenu du fichier ne semble pas avoir été corrigé. Pas sûr que ce soit vrai pour tous les contenus et toutes les versions du système d'exploitation, essayez-le.
Dans Xcode 8 et iOS 10 pour déterminer la hauteur d'une vue Web. Vous pouvez obtenir cette hauteur avec
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
CGFloat height = [[webView stringByEvaluatingJavaScriptFromString:@"document.body.scrollHeight"] floatValue];
NSLog(@"Webview height is:: %f", height);
}
OU pour Swift
func webViewDidFinishLoad(aWebView:UIWebView){
let height: Float = (aWebView.stringByEvaluatingJavaScriptFromString("document.body.scrollHeight")?.toFloat())!
print("Webview height is::\(height)")
}
Une solution simple consisterait simplement à utiliser webView.scrollView.contentSize
mais je ne sais pas si cela fonctionne avec JavaScript. Si aucun JavaScript n'est utilisé, cela fonctionne à coup sûr:
- (void)webViewDidFinishLoad:(UIWebView *)aWebView {
CGSize contentSize = aWebView.scrollView.contentSize;
NSLog(@"webView contentSize: %@", NSStringFromCGSize(contentSize));
}
C'est bizarre!
J'ai testé les solutions à la fois sizeThatFits:
et [webView stringByEvaluatingJavaScriptFromString:@"document.body.scrollHeight"]
sont PAS travaille pour moi.
Cependant, j'ai trouvé un moyen facile et intéressant d'obtenir la bonne hauteur de contenu de page Web. Actuellement, je l’utilise dans ma méthode déléguée scrollViewDidScroll:
.
CGFloat contentHeight = scrollView.contentSize.height - CGRectGetHeight(scrollView.frame);
Vérifié dans iOS 9.3 Simulator/Device, bonne chance!
EDIT:
Arrière-plan: le contenu html est calculé par ma variable chaîne et mon modèle de contenu HTTP, chargé par la méthode loadHTMLString:baseURL:
, pas de scripts JS enregistrés.
Pour iOS10, j'obtenais 0 (zéro) valeur de document.height
alors document.body.scrollHeight
est la solution pour obtenir une hauteur de document dans Webview. Le problème peut également être résolu pour width
.
Autant que je sache, vous pouvez utiliser [webView sizeThatFits:CGSizeZero]
pour déterminer sa taille.
Lorsque vous utilisez webview en tant que sous-vue quelque part dans scrollview, vous pouvez définir la contrainte de hauteur sur une valeur constante, puis en créer une sortie et l'utiliser de la manière suivante:
- (void)webViewDidFinishLoad:(UIWebView *)webView {
webView.scrollView.scrollEnabled = NO;
_webViewHeight.constant = webView.scrollView.contentSize.height;
}
Aucune des suggestions ici ne m'a aidé avec ma situation, mais j'ai lu quelque chose qui m'a donné une réponse. J'ai un ViewController avec un ensemble fixe de contrôles d'interface utilisateur suivi d'un UIWebView. Je voulais que toute la page défile comme si les contrôles de l'interface utilisateur étaient connectés au contenu HTML. Je désactive donc le défilement sur UIWebView et dois ensuite définir correctement la taille du contenu d'une vue de défilement parent.
Le conseil important s’est avéré que UIWebView ne signale pas correctement sa taille tant qu’il n’a pas été rendu à l’écran. Ainsi, lorsque je charge le contenu, je règle la taille du contenu sur la hauteur d'écran disponible. Ensuite, dans viewDidAppear, je mets à jour la taille du contenu de scrollview. Cela a fonctionné pour moi parce que j'appelle loadHTMLString sur du contenu local. Si vous utilisez loadRequest, vous devrez peut-être également mettre à jour le contentSize dans webViewDidFinishLoad, en fonction de la vitesse d'extraction du code HTML.
Il n'y a pas de scintillement, car seule la partie invisible de la vue de défilement est modifiée.
J'utilise un UIWebView
qui n'est pas une sous-vue (et ne fait donc pas partie de la hiérarchie des fenêtres) pour déterminer la taille du contenu HTML pour UITableViewCells
. J'ai trouvé que le UIWebView
déconnecté ne rapporte pas correctement sa taille avec -[UIWebView sizeThatFits:]
. De plus, comme indiqué dans https://stackoverflow.com/a/3937599/9636 , vous devez définir le UIWebView
's frame
height
sur 1 afin d'obtenir la bonne hauteur du tout.
Si la hauteur de UIWebView
est trop grande (c'est-à-dire que vous l'avez définie sur 1000, mais que la taille du contenu HTML n'est que de 500):
UIWebView.scrollView.contentSize.height
-[UIWebView stringByEvaluatingJavaScriptFromString:@"document.height"]
-[UIWebView sizeThatFits:]
Tous renvoient un height
de 1000.
Pour résoudre mon problème dans ce cas, j'ai utilisé https://stackoverflow.com/a/11770883/9636 , ce que j'ai consciencieusement voté. Cependant, je n’utilise cette solution que lorsque mon UIWebView.frame.width
est le même que le -[UIWebView sizeThatFits:]
width
.
Si votre code HTML contient lourd Des contenus HTML tels que ceux d'iframe (c'est-à-dire facebook, Twitter, instagram-embeds), la vraie solution est beaucoup plus difficile, commencez par envelopper votre code 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>"];
Ajoutez ensuite le traitement x-update-webview-height - à votre shouldStartLoadWithRequest :
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;
}
...
Et enfin, ajoutez le code suivant dans votre 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.
...
P.S. Vous pouvez implémenter un délai (SetTimeout et setInterval) dans votre code ObjectiveC/Swift - à vous de choisir.
P.S.S. Informations importantes sur UIWebView et Facebook Embeds: La publication Facebook intégrée ne s'affiche pas correctement dans UIWebView
Je suis aussi bloqué sur ce problème, puis je me suis rendu compte que si je veux calculer la hauteur dynamique de la webView, je dois d'abord dire la largeur de la webView, donc j'ajoute une ligne avant js et il s'avère que je peux obtenir hauteur réelle très précise.
Le code est simple comme ceci:
-(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
Délégué:let height = webView.scrollView.contentSize.height
Sans l'étape 1, si webview.height> content contentHeight, l'étape 2 renverra webview.height mais pas la taille du contenu.height.
Toujours dans iOS 7 pour le bon fonctionnement de toutes les méthodes mentionnées, ajoutez ceci dans votre méthode de contrôleur de vue viewDidLoad
:
if ([self respondsToSelector:@selector(automaticallyAdjustsScrollViewInsets)]) {
self.automaticallyAdjustsScrollViewInsets = NO;
}
Sinon, aucune des méthodes ne fonctionnerait comme il se doit.