Make a Uiwebview as Height as Its Content with Auto Layout

Make a UIWebView as height as its content with Auto Layout

To make this work you have to do the following steps:

  1. Connect the UIWebView from the nib to an outlet in your view controller
  2. Disable scrolling in the web view
  3. Set the constraints on the UIScrollView, the UIView on top of the web view (In my example I omitted all the labels in that view) and the UIWebView.
  4. Connect the UIWebView's height constraint to an outlet in your view controller.
  5. Set the view controller as UIWebViewDelegate
  6. In webViewDidFinishLoad set the height constraint's constant to the height of the contentSize of the scroll view inside the web view.
  7. 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:

Sample Image

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



Leave a reply



Submit