Make a UIWebView as height as its content with Auto Layout
To make this work you have to do the following steps:
- Connect the
UIWebView
from the nib to an outlet in your view controller - Disable scrolling in the web view
- Set the constraints on the
UIScrollView
, theUIView
on top of the web view (In my example I omitted all the labels in that view) and theUIWebView
. - Connect the UIWebView's
height
constraint to an outlet in your view controller. - Set the view controller as
UIWebViewDelegate
- In
webViewDidFinishLoad
set the height constraint's constant to the height of thecontentSize
of the scroll view inside the web view. - Start Key-Value Observing on the contentSize to change the height, when height of the web view has to change because segments of the webpage change their size without reloading the page (like accordeons, or menus).
I won't explain the constraints in detail as you seem to already have figured them out yourself. Here is a screenshot of the constraints:
So, here is the code:
import UIKit
var MyObservationContext = 0
class ViewController: UIViewController {
@IBOutlet weak var webview: UIWebView!
@IBOutlet weak var webviewHeightConstraint: NSLayoutConstraint!
var observing = false
override func viewDidLoad() {
super.viewDidLoad()
webview.scrollView.scrollEnabled = false
webview.delegate = self
webview.loadRequest(NSURLRequest(URL: NSURL(string: "https://www.google.de/intl/de/policies/terms/regional.html")!))
}
deinit {
stopObservingHeight()
}
func startObservingHeight() {
let options = NSKeyValueObservingOptions([.New])
webview.scrollView.addObserver(self, forKeyPath: "contentSize", options: options, context: &MyObservationContext)
observing = true;
}
func stopObservingHeight() {
webview.scrollView.removeObserver(self, forKeyPath: "contentSize", context: &MyObservationContext)
observing = false
}
override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
guard let keyPath = keyPath else {
super.observeValueForKeyPath(nil, ofObject: object, change: change, context: context)
return
}
switch (keyPath, context) {
case("contentSize", &MyObservationContext):
webviewHeightConstraint.constant = webview.scrollView.contentSize.height
default:
super.observeValueForKeyPath(keyPath, ofObject: object, change: change, context: context)
}
}
}
extension ViewController: UIWebViewDelegate {
func webViewDidFinishLoad(webView: UIWebView) {
print(webView.request?.URL)
webviewHeightConstraint.constant = webview.scrollView.contentSize.height
if (!observing) {
startObservingHeight()
}
}
}
UIWebView with dynamic height inside a UIScrollView in Objective-C
add a height constraint to your webView and make a IBOutlet of that like
@property(strong, nonatomic) IBOutlet NSLayoutConstraint *webViewHeightConstraint;
load your webview and in web view delegate
- (void)webViewDidFinishLoad:(UIWebView *)webView
get webview content height and set webViewHeightConstraint.constant
like below:-
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
NSString *str = [webView stringByEvaluatingJavaScriptFromString:@"(document.height !== undefined) ? document.height : document.body.offsetHeight;"];
CGFloat height = str.floatValue;
webViewHeightConstraint.constant = height;
}
hope it may help you.
how to manage Height of UITableHeaderView in based on webview content using auto layout
I would suggest these steps:
First, declare webViewHeight
as class variable so it can be access by all functions.
var webViewHeight: CGFloat = 0.0
Then, get the height of the UIWebView content height. Make sure you have set the UIWebView delegate in viewForHeaderInSection
func webViewDidFinishLoad(webView: UIWebView) {
// check if webview finished loading
if !webView.isLoading {
if webViewHeight == 0 {
// get webview height
webViewHeight = webView.scrollView.contentSize.height
}
// then reload tableView
myTableView.reloadData()
}
}
It should update in
func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return webViewHeight
}
Dynamic UIView height with auto layout in iOS 6
You are setting the height contraint of your webView as 266. That's why the height of the web view is still fixed.
You can create this height constraint as an IBOutlet, for example:
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *webViewHeightConstraint;
And then you can modify the constant of the height constraint when the web view has finished downloading the content. The web view itself consists of scroll view inside, so if you want to get the overall height of the content:
- (void)webViewDidFinishLoad:(UIWebView *)webView {
self.webViewHeightConstraint.constant = self.webView.scrollView.contentSize.height;
}
Or apparently this one also works:
- (void)webViewDidFinishLoad:(UIWebView *)webView {
[self.webView sizeToFit];
self.webViewHeightConstraint.constant = self.webView.frame.size.height;
}
UIWebView auto height size
This worked for me:
let it = Double(webView.stringByEvaluatingJavaScript(from: "document.documentElement.scrollHeight") ?? "0")
UITableViewCell with UIWebview that adjusts height to content size
The auto layout approach might be tricky. An easier approach is to just set the frame of the corresponding cell in webViewDidFinishLoad
. You can use cellForRowAtIndexPath
on the table view to get the displayed cell (it won't try to get the cell from the UITableViewDataSource
if it's already displayed because it'll be cached).
- (void)webViewDidFinishLoad:(UIWebView *)webView {
if (_contentHeights[webView.tag]) {
return;
}
float height = [NSNumber numberWithFloat:[[webView stringByEvaluatingJavaScriptFromString:@"document.body.offsetHeight;"] floatValue]];
NSIndexPath* indexOfCell = [NSIndexPath indexPathForRow:webView.tag inSection:0];
UITableViewCell* cell = [self.tableView cellForRowAtIndexPath:indexOfCell];
cell.frame = CGRectMake(0, 0, cell.frame.size.width, height);
}
UIWebView dynamic content size
This post has been updated for Swift 5 & WKWebView
So this is a really great function you wrote there, OP!
Here is just a shorter, more elegant version of your code:
// make sure to declare the delegate when creating your webView (add UIWebViewDelegate to class declaration as well)
myWebView.delegate = self
func webViewDidFinishLoad(webView: UIWebView) {
webView.frame.size.height = 1
webView.frame.size = webView.sizeThatFits(CGSize.zero)
}
Migrating to WKWebView
1) import WebKit
2) make your ViewController
inherit from WKNavigationDelegate
3) hook up the WKWebView
’s delegate: webView.navigationDelegate = self
4) implement the following protocol function:
webView(_ webView: WKWebView, didFinish navigation: WKNavigation!)
After migrating from UIWebView
to WKWebView
, above approach doesn’t seem to work anymore.
What you can do instead, is change the line with webView.sizeThatFits(CGSize.zero)
to:
webView.frame.size = webView.scrollView.contentSize
The full code for WKWebView
would then be:
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
webView.frame.size.height = 1
webView.frame.size = webView.scrollView.contentSize
}
Related Topics
iOS 10 Issue: Uiscrollview Not Scrolling, Even When Contentsize Is Set
Core Data Entity Unique Constraint Does Not Work
Pass Data from View Controller to Child Controller in Swift
App Crashes When User Starts Typing in Uisearchbar
Cannot Set Color of Button's Label Inside Menu in Swiftui
Fbsdkcorekit.Framework/Fbsdkcorekit: No Matching Architecture in Universal Wrapper
Wake Up Application in Background Using Audiosession Like Alarmy iOS App
Playing an Audio File Repeatedly with Avaudioengine
Present Specific View Controller in Didreceiveremotenotification with Swift
How to Run a Task in Swift on a Particular Date-Time in Background Either Application Is on or Off
How to Use Type Erasure with a Protocol Using Associated Type
iOS Swift - Custom Camera Overlay
Swift 1.2 and Parse: Issue with Retrieving Images to Populate Pfquerycollectionviewcontroller
How to Use Nsuserdefaults to Store an Array of Custom Classes in Swift
Openurl in Appdelegate Conversion Error Nsstring -> String (Swift & iOS8)