У мене є UIWebView
різний (одна сторінка) вміст. Я хотів би дізнатися CGSize
вміст, щоб належним чином змінити перегляд батьків. Очевидний, -sizeThatFits:
на жаль, просто повертає поточний розмір кадру webView.
У мене є UIWebView
різний (одна сторінка) вміст. Я хотів би дізнатися CGSize
вміст, щоб належним чином змінити перегляд батьків. Очевидний, -sizeThatFits:
на жаль, просто повертає поточний розмір кадру webView.
Відповіді:
Виявилося, що моя перша здогадка про використання -sizeThatFits:
була не зовсім помилковою. Здається, це працює, але лише якщо рамка веб-перегляду встановлена на мінімальний розмір до надсилання -sizeThatFits:
. Після цього ми можемо виправити неправильний розмір кадру за розміром, що підходить. Це звучить жахливо, але насправді це не так вже й погано. Оскільки ми обидва зміни кадру робимо один за одним, подання не оновлюється і не мерехтить.
Звичайно, нам доведеться чекати, поки вміст не буде завантажений, тому ми вводимо код у -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);
}
Швидкий 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
}
Слід зазначити, що існує інший підхід (спасибі @GregInYEG) із використанням JavaScript. Не впевнений, яке рішення працює краще.
З двох химерних рішень мені це більше подобається.
UIWebView
показник вище, ніж ваш батьківський вигляд, вам потрібно вбудувати його в UIScrollView
.
У мене є ще одне рішення, яке чудово працює.
З одного боку, підхід та рішення Ortwin працює лише з iOS 6.0 та новішими версіями, але не працює належним чином на iOS 5.0, 5.1 та 5.1.1, а з іншого - це те, що мені не подобається і не можу зрозуміти з підходом Ортвіна, це використання методу [webView sizeThatFits:CGSizeZero]
з параметром CGSizeZero
: Якщо ви читаєте офіційну документацію Apple про цей метод та його параметр, він чітко говорить:
Реалізація за замовчуванням цього методу повертає частину розміру прямокутника меж перегляду. Підкласи можуть замінити цей метод, щоб повернути спеціальне значення на основі бажаного макета будь-яких підпрезентацій. Наприклад, об'єкт UISwitch повертає значення фіксованого розміру, яке представляє стандартний розмір перегляду комутатора, а об’єкт UIImageView повертає розмір зображення, яке він відображає в даний час.
Я маю на увазі те, що це наче він натрапив на своє рішення без будь-якої логіки, тому що, читаючи документацію, параметр, який передається, [webView sizeThatFits: ...]
повинен хоча б мати бажане width
. З його розчином бажаної шириною встановлюються на webView
раму «s перед викликом sizeThatFits
з CGSizeZero
параметром. Тому я вважаю, що це рішення працює на iOS 6 "випадково".
Я уявив більш раціональний підхід, який має перевагу роботи для iOS 5.0 і пізніших версій ... А також у складних ситуаціях, коли більше одного веб-перегляду (з його властивістю webView.scrollView.scrollEnabled = NO
вбудовано в a scrollView
.
Ось мій код, щоб змусити макет webView
потрібного width
і повернути відповідний height
набір до webView
себе:
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.
}
Швидкий 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;
}
Зверніть увагу , що в моєму прикладі, webView
був вбудований в звичай , scrollView
що має інше webViews
... Все це webViews
було їх webView.scrollView.scrollEnabled = NO
, і останній шматок коду , який я повинен був додати був обчислення height
з contentSize
мого звичаю scrollView
вкладення їх webViews
, але це було так легко а підсумовуючи мій webView
«и frame.size.height
обчислюється за допомогою трюку описано вище ...
-[UIWebView scrollView]
доступний лише в iOS 5.0 або новішої версії.
Воскрешаючи це запитання, тому що я знайшов відповідь Ортвіна лише на МОСТЬ часу ...
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
}
}
Оновлення: Я виявив, як згадувалося в коментарях, це, схоже, не сприймає випадок, коли вміст зменшився. Не впевнений, чи це правда для всього вмісту та версії ОС, спробуйте.
webView.scalesPageToFit = YES
як @Sijo, зазначений у коментарі вище.
У Xcode 8 та iOS 10 для визначення висоти веб-перегляду. Ви можете отримати висоту за допомогою
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
CGFloat height = [[webView stringByEvaluatingJavaScriptFromString:@"document.body.scrollHeight"] floatValue];
NSLog(@"Webview height is:: %f", height);
}
АБО для Swift
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 Simulator / Device, удачі!
Редагувати:
Передумови: Вміст html обчислюється за моєю змінною рядка та шаблоном вмісту HTTP, завантаженою методом loadHTMLString:baseURL:
, немає зареєстрованих сценаріїв JS.
Я використовую UIWebView
те, що не є підглядом (і, отже, не є частиною ієрархії вікон) для визначення розмірів вмісту HTML для UITableViewCells
. Я виявив, що відключений 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:]
Усі повертають height
1000.
Щоб вирішити свою проблему в цьому випадку, я використав https://stackoverflow.com/a/11770883/9636 , яку я гідно проголосував. Однак я використовую це рішення лише тоді, коли мій UIWebView.frame.width
такий самий, як і -[UIWebView sizeThatFits:]
width
.
Жодна із пропозицій тут не допомогла мені зі своєю ситуацією, але я прочитав щось, що дало мені відповідь. У мене є ViewController з фіксованим набором елементів користувальницького інтерфейсу, за яким слід UIWebView. Я хотів, щоб вся сторінка прокручувалася так, ніби елементи керування інтерфейсом були підключені до вмісту HTML, тому я відключаю прокрутку на UIWebView і повинен правильно встановити розмір вмісту батьківського перегляду прокрутки.
Важливим підказом виявилось те, що UIWebView не повідомляє про свій розмір правильно, доки не буде виведено на екран. Тому коли я завантажую вміст, я встановлюю розмір вмісту на доступну висоту екрана. Потім в viewDidAppear я поновлюю розмір вмісту прокрутки до правильного значення. Це працювало для мене, тому що я викликаю loadHTMLString на локальному вмісті. Якщо ви використовуєте loadRequest, можливо, знадобиться оновити contentSize у webViewDidFinishLoad також залежно від швидкості отримання файлу html.
Не буває мерехтіння, оскільки змінюється лише невидима частина перегляду прокрутки.
webViewDidFinishLoad
безпечний підхід.
Якщо ваш HTML містить важкий HTML-вміст, наприклад iframe (тобто 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>"];
Потім додайте керування x-update-webview-height -sheme в свою слідStartLoadWithRequest :
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;
}
...
І, нарешті, додайте такий код у свій макетSubviews :
...
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.
...
PS Ви можете впроваджувати затримку часу (SetTimeout та setInterval) всередині вашого ObjectiveC / Swift-коду - саме вам.
PSS Важлива інформація про UIWebView та Facebook Вбудовування : Вбудований пост у Facebook не відображається належним чином у UIWebView
Використовуючи веб-перегляд як підвид, десь у перегляді прокрутки, ви можете встановити обмеження висоти на якесь постійне значення, а пізніше зробити з нього розетку і використовувати її як:
- (void)webViewDidFinishLoad:(UIWebView *)webView {
webView.scrollView.scrollEnabled = NO;
_webViewHeight.constant = webView.scrollView.contentSize.height;
}
Я також зациклювався на цій проблемі, тоді я зрозумів, що якщо я хочу обчислити динамічну висоту webView, мені потрібно спочатку сказати ширину webView, тому я додаю один рядок перед js, і виявиться, що я можу отримати дуже точна фактична висота.
Код простий так:
-(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, але не contentize.height.
Також в iOS 7 для належної роботи всіх згаданих методів додайте це у свій viewDidLoad
метод контролера перегляду :
if ([self respondsToSelector:@selector(automaticallyAdjustsScrollViewInsets)]) {
self.automaticallyAdjustsScrollViewInsets = NO;
}
Інакше жоден із методів не працював би як слід.