ฉันมีเนื้อหาที่UIWebView
แตกต่างกัน (หน้าเดียว) ฉันต้องการค้นหาCGSize
เนื้อหาเพื่อปรับขนาดมุมมองของผู้ปกครองให้เหมาะสม สิ่งที่เห็นได้ชัดคือ-sizeThatFits:
เพียงแค่ส่งคืนขนาดเฟรมปัจจุบันของ webView
ฉันมีเนื้อหาที่UIWebView
แตกต่างกัน (หน้าเดียว) ฉันต้องการค้นหาCGSize
เนื้อหาเพื่อปรับขนาดมุมมองของผู้ปกครองให้เหมาะสม สิ่งที่เห็นได้ชัดคือ-sizeThatFits:
เพียงแค่ส่งคืนขนาดเฟรมปัจจุบันของ webView
คำตอบ:
ปรากฎว่าการเดาครั้งแรกของฉันโดยใช้-sizeThatFits:
ไม่ผิดทั้งหมด มันดูเหมือนว่าจะทำงาน แต่ถ้ากรอบ WebView -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 และในทางกลับกันมีบางอย่างที่ฉันไม่ชอบและไม่เข้าใจ ด้วยวิธีการของ Ortwin เป็นการใช้วิธีการ[webView sizeThatFits:CGSizeZero]
กับพารามิเตอร์CGSizeZero
: หากคุณอ่านเอกสารอย่างเป็นทางการของ Apple เกี่ยวกับวิธีการนี้และพารามิเตอร์จะระบุไว้อย่างชัดเจน:
การใช้งานตามค่าเริ่มต้นของวิธีนี้จะส่งคืนส่วนขนาดของสี่เหลี่ยมผืนผ้าขอบเขตของมุมมอง คลาสย่อยสามารถแทนที่เมธอดนี้เพื่อส่งคืนค่าที่กำหนดเองตามเค้าโครงที่ต้องการของมุมมองย่อยใด ๆ ตัวอย่างเช่นออบเจ็กต์ UISwitch จะส่งคืนค่าขนาดคงที่ซึ่งแสดงถึงขนาดมาตรฐานของมุมมองสวิตช์และวัตถุ UIImageView จะส่งกลับขนาดของรูปภาพที่กำลังแสดงอยู่
สิ่งที่ฉันหมายความว่ามันเป็นเหมือนเขามาในการแก้ปัญหาของเขาโดยไม่มีตรรกะใด ๆ เพราะการอ่านเอกสารพารามิเตอร์ที่ส่งผ่านไปอย่างน้อยควรได้ตามที่ต้องการ[webView sizeThatFits: ...]
width
ด้วยวิธีการแก้ปัญหาของเขาความกว้างที่ต้องการจะถูกตั้งค่าwebView
เป็นเฟรมก่อนที่จะเรียกsizeThatFits
ด้วยCGSizeZero
พารามิเตอร์ ดังนั้นฉันจึงดูแลให้โซลูชันนี้ทำงานบน iOS 6 โดย "บังเอิญ"
ฉันจินตนาการถึงวิธีการที่มีเหตุผลมากขึ้นซึ่งมีข้อได้เปรียบในการทำงานกับ iOS 5.0 และใหม่กว่า ... และในสถานการณ์ที่ซับซ้อนซึ่งมี webView มากกว่าหนึ่งรายการ (ด้วยคุณสมบัติwebView.scrollView.scrollEnabled = NO
นั้นฝังอยู่ในไฟล์scrollView
.
นี่คือรหัสของฉันในการบังคับ Layout ของ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
's frame.size.height
คำนวณด้วยเคล็ดลับที่อธิบายข้างต้น ...
-[UIWebView scrollView]
มีให้บริการใน iOS 5.0 หรือใหม่กว่าเท่านั้น
การรื้อฟื้นคำถามนี้เพราะฉันพบคำตอบของ 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
}
}
อัปเดต: ฉันพบว่าตามที่กล่าวไว้ในความคิดเห็นนี้ดูเหมือนจะไม่ตรงกับกรณีที่เนื้อหาหดตัว ไม่แน่ใจว่าเป็นความจริงสำหรับเนื้อหาและเวอร์ชันระบบปฏิบัติการทั้งหมดหรือไม่ลองดู
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));
}
AFAIK คุณสามารถใช้[webView sizeThatFits:CGSizeZero]
เพื่อหาขนาดเนื้อหาได้
นี่มันแปลก!
ผมทดสอบการแก้ปัญหาทั้งสอง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 ที่ลงทะเบียนที่นั่น
สำหรับ iOS10 ฉันได้รับค่า 0 (ศูนย์) document.height
ดังนั้นจึงdocument.body.scrollHeight
เป็นวิธีแก้ปัญหาในการรับความสูงของเอกสารใน Webview width
ปัญหาที่สามารถแก้ไขได้ยัง
ฉันใช้UIWebView
ที่ไม่ได้เป็น subview (และดังนั้นจึงไม่เป็นส่วนหนึ่งของลำดับชั้นหน้าต่าง) ในการกำหนดขนาดของเนื้อหา HTML UITableViewCells
สำหรับ ผมพบว่าการเชื่อมต่อไม่รายงานขนาดของมันอย่างถูกต้องกับUIWebView
-[UIWebView sizeThatFits:]
นอกจากนี้ตามที่ระบุไว้ในhttps://stackoverflow.com/a/3937599/9636คุณต้องตั้งค่าUIWebView
เป็นframe
height
1 เพื่อให้ได้ความสูงที่เหมาะสม
หากUIWebView
ความสูงใหญ่เกินไป (เช่นคุณตั้งค่าเป็น 1,000 แต่ขนาดเนื้อหา HTML เพียง 500):
UIWebView.scrollView.contentSize.height
-[UIWebView stringByEvaluatingJavaScriptFromString:@"document.height"]
-[UIWebView sizeThatFits:]
ส่งคืนทั้งหมดheight
1,000
เพื่อแก้ปัญหาของฉันในกรณีนี้ฉันใช้https://stackoverflow.com/a/11770883/9636ซึ่งฉันลงคะแนนตามหน้าที่ อย่างไรก็ตามฉันจะใช้วิธีแก้ปัญหานี้ก็ต่อเมื่อฉันUIWebView.frame.width
เหมือนกับไฟล์-[UIWebView sizeThatFits:]
width
.
คำแนะนำใด ๆ ที่นี่ไม่ช่วยฉันในเรื่องสถานการณ์ แต่ฉันได้อ่านบางสิ่งที่ให้คำตอบแก่ฉัน ฉันมี ViewController ที่มีชุดควบคุม UI คงที่ตามด้วย UIWebView ฉันต้องการให้ทั้งหน้าเลื่อนราวกับว่าส่วนควบคุม UI เชื่อมต่อกับเนื้อหา HTML ดังนั้นฉันจึงปิดใช้งานการเลื่อนบน UIWebView จากนั้นต้องตั้งค่าขนาดเนื้อหาของมุมมองการเลื่อนหลักให้ถูกต้อง
เคล็ดลับที่สำคัญคือ UIWebView ไม่รายงานขนาดอย่างถูกต้องจนกว่าจะแสดงผลบนหน้าจอ ดังนั้นเมื่อฉันโหลดเนื้อหาฉันตั้งค่าขนาดเนื้อหาตามความสูงของหน้าจอที่มี จากนั้นใน viewDidAppear ฉันอัปเดตขนาดเนื้อหาของ scrollview เป็นค่าที่ถูกต้อง สิ่งนี้ใช้ได้ผลสำหรับฉันเพราะฉันกำลังเรียก 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 -scheme ใน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;
}
...
และในที่สุดก็เพิ่มรหัสต่อไปภายในของคุณ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.
...
ป.ล. คุณสามารถใช้การหน่วงเวลา (SetTimeout และ setInterval) ภายใน ObjectiveC / Swift-code ได้ขึ้นอยู่กับคุณ
PSS ข้อมูลสำคัญเกี่ยวกับ UIWebView และการฝัง Facebook: โพสต์ Facebook แบบฝังแสดงไม่ถูกต้องใน UIWebView
เมื่อใช้ webview เป็นมุมมองย่อยที่ใดที่หนึ่งใน scrollview คุณสามารถตั้งค่าความสูงเป็นค่าคงที่และสร้างทางออกจากมันในภายหลังและใช้มันเช่น:
- (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
Delegate:let height = webView.scrollView.contentSize.height
หากไม่มี step1 ถ้า webview.height> real contentHeight ขั้นตอนที่ 2 จะส่งคืน webview.height แต่ไม่รวม contentize.height
นอกจากนี้ใน iOS 7 สำหรับการทำงานที่เหมาะสมของวิธีการที่กล่าวถึงทั้งหมดให้เพิ่มสิ่งนี้ในviewDidLoad
วิธีการควบคุมมุมมองของคุณ:
if ([self respondsToSelector:@selector(automaticallyAdjustsScrollViewInsets)]) {
self.automaticallyAdjustsScrollViewInsets = NO;
}
มิฉะนั้นทั้งสองวิธีจะไม่ได้ผลเท่าที่ควร