UIWebView dynamic content size

2019-01-12 00:24发布

问题:

I've been looking around and wasnt able to see any swift related ways to do this. I'm trying to get my UIWebViews height to be dynamic. I have a UIWebView that loads data using the loadHtmlString function.The thing is that I am loading the data from an sqlite database, each time I load a different string with different length and naturally the web view obtains different height.
Now I need to know how to make the UIWebView that exact height in order to load my next content right under the webView. This is what I have so far

var jobSkillView = UIWebView(frame: CGRectMake(-5, 480.0, screenWidth, 300.0))
jobSkillView.loadHTMLString("<html><body p style='font-family:arial;font-size:16px;'>" + jobSkills + "</body></html>", baseURL: nil)
jobSkillView.stringByEvaluatingJavaScriptFromString("document.body.innerHTML")
jobSkillView.scrollView.scrollEnabled = true
jobSkillView.scrollView.bounces = true
jobSkillView.sizeToFit()
border.addSubview(jobSkillView)

I found something like this on SO but not sure how to link it to the UIWebView's frame:

func webViewDidFinishLoad(jobSkillView : UIWebView){
    // Change the height dynamically of the UIWebView to match the html content
    var jobSkillViewFrame: CGRect = jobSkillView.frame
    jobSkillViewFrame.size.height = 1
    jobSkillView.frame = jobSkillViewFrame
    var fittingSize: CGSize = (jobSkillView.sizeThatFits(CGSizeZero))
    jobSkillViewFrame.size = fittingSize
    // webViewFrame.size.width = 276; Making sure that the webView doesn't get wider than 276 px
    jobSkillView.frame = jobSkillViewFrame
    var jobSkillViewHeight = jobSkillView.frame.size.height
}

回答1:

This post has been updated for Swift 4 & 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
}


回答2:

this only worked for me

func webViewDidFinishLoad(_ webView: UIWebView) {
    webView.frame.size.height = 1
    webView.frame.size = webView.sizeThatFits(.zero)
    webView.scrollView.isScrollEnabled=false;
    myWebViewHeightConstraint.constant = webView.scrollView.contentSize.height
    webView.scalesPageToFit = true
}

make sure you've created an outlet for myWebViewHeightConstraint



回答3:

Here is my custom class to work with custom UIWebViews, it has everything in it to get the correct scrollview content height, set UIWebView height and create a custom height constraint to get autolayout working. It also loads some custom CSS styling...

class CustomUIWebView: UIWebView, UIWebViewDelegate {

    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        self.scrollView.scrollEnabled = false
        self.scrollView.bounces = false
        self.delegate = self
    }

    override init(frame: CGRect) {
        super.init(frame: frame)
        self.scrollView.scrollEnabled = false
        self.scrollView.bounces = false
        self.delegate = self
    }

    override func loadHTMLString(string: String!, baseURL: NSURL!) {
        var cssURL:String = NSBundle.mainBundle().pathForResource("webview", ofType: "css")!
        var s:String = "<html><head><title></title><meta name=\"viewport\" content=\"initial-scale=1, user-scalable=no, width=device-width\" /><link rel=\"stylesheet\" href=\"./webview.css\" ></link></head><body>"+string+"</body></html>";
        var url:NSURL

        if baseURL == nil {
            url = NSBundle.mainBundle().bundleURL
        } else {
            url = baseURL
        }

        super.loadHTMLString(s, baseURL: url)
    }

    func webViewDidFinishLoad(webView: UIWebView) {
        self.webViewResizeToContent(webView)
    }

    func webViewResizeToContent(webView: UIWebView) {
        webView.layoutSubviews()

        // Set to smallest rect value
        var frame:CGRect = webView.frame
        frame.size.height = 1.0
        webView.frame = frame

        var height:CGFloat = webView.scrollView.contentSize.height
        println("UIWebView.height: \(height)")

        webView.setHeight(height: height)
        let heightConstraint = NSLayoutConstraint(item: webView, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.Height, multiplier: 1.0, constant: height)
        webView.addConstraint(heightConstraint)

        // Set layout flag
        webView.window?.setNeedsUpdateConstraints()
        webView.window?.setNeedsLayout()
    }

}


回答4:

I had problem with:

let height = webView.scrollView.contentSize.height

Sometimes my web view height simply didn't calculacte and stayed on default value. So finally I manage to find better solution that works fine, just replace that line code with:

let height = webView.stringByEvaluatingJavaScript(from: "document.body.scrollHeight")

This is mine final complete code:

    func webViewDidFinishLoad(_ webView: UIWebView) {

    //webview height
    webView.frame.size.height = 1
    webView.frame.size = webView.sizeThatFits(.zero)
    webView.scrollView.isScrollEnabled = false
    let height = webView.stringByEvaluatingJavaScript(from: "document.body.scrollHeight")
    if let height = height {
        if let heightInt = Int(height) {
            let heightFloat = Float(heightInt)

            webViewHeightConstraint.constant = CGFloat(heightFloat)
        }
    }
    webView.scalesPageToFit = true
}


回答5:

Okay I figured out what I was doing wrong so now I know how to call this function. First of all I was supposed to call a UIWebViewDelegate in my class. Then set my var jobSkillView to (jobSkillView.delegate = self). Now this is where I made my major mistake. In my code I had a if else statement that I was throwing my func webViewDidLoad in. I was supposed to put it out of that statement and into the actual class to override my frame for the UIWebView. Speaking of frame **** DONT FORGET TO SET YOUR FRAME HEIGHT TO 1. Then and only then this function will work for your UIWebView. After that you should have a fully functional based height for your UIWebView for Swift.



回答6:

Use the following code to make your UIWebView height dynamic in Swift 3.x

func webViewDidFinishLoad(_ webView: UIWebView) {        

 let height = webView.scrollView.contentSize.height
 var wRect = webView.frame
 wRect.size.height = height
 webView.frame = wRect

}


回答7:

you can use this class for makking webview size to fit for swift 3 and swift 4

//
//  RSWebView.swift
//  CustumWebViewDemo
//
//  Created by Ruchin Somal on 01/01/18.
//  Copyright © 2018 Ruchin Somal. All rights reserved.
//

import UIKit

class RSWebView: UIWebView, UIWebViewDelegate {

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)!
        self.scrollView.isScrollEnabled = false
        self.scrollView.bounces = false
        self.delegate = self
    }

    override init(frame: CGRect) {
        super.init(frame: frame)
        self.scrollView.isScrollEnabled = false
        self.scrollView.bounces = false
        self.delegate = self
    }

    override func loadHTMLString(_ string: String?, baseURL: URL?) {
        let s:String = "<html><head><title></title><meta name=\"viewport\" content=\"initial-scale=1, user-scalable=no, width=device-width\" /><link rel=\"stylesheet\" href=\"./webview.css\" ></link></head><body>"+string!+"</body></html>";
        var url:URL

        if baseURL == nil {
            url = Bundle.main.bundleURL
        } else {
            url = baseURL!
        }

        super.loadHTMLString(s, baseURL: url)
    }

    func webViewDidFinishLoad(_ webView: UIWebView) {
        self.webViewResizeToContent(webView: webView)
    }

    func webViewResizeToContent(webView: UIWebView) {
        webView.layoutSubviews()

        // Set to initial value of webview
        var frame:CGRect = webView.frame
        frame.size.height = 1.0
        webView.frame = frame

        // Calculated height of webview
        let wvheight: CGFloat = webView.scrollView.contentSize.height
        print("UIWebView.height: \(wvheight)")
        var wvRect = webView.frame
        wvRect.size.height = wvheight
        webView.frame = wvRect

        let heightConstraint = NSLayoutConstraint(item: webView, attribute: NSLayoutAttribute.height, relatedBy: NSLayoutRelation.equal, toItem: nil, attribute: NSLayoutAttribute.height, multiplier: 1.0, constant: wvheight)
        webView.addConstraint(heightConstraint)

        webView.window?.setNeedsUpdateConstraints()
        webView.window?.setNeedsLayout()
    }

}


回答8:

When font change at that time change Webview height to 1 than get proper offsetHeight for Webview

webView1.frame.size.height = 1