【问题标题】:Make a UIWebView as height as its content with Auto Layout使用自动布局使 UIWebView 与其内容一样高
【发布时间】:2015-10-21 14:51:53
【问题描述】:

我在滚动视图中嵌入了一个网络视图,我希望将网络视图“展开”以显示其所有内容,然后我想用我的滚动视图滚动浏览这些内容。

我使用滚动视图作为超级视图而不只是将 Web 视图用作滚动视图的原因是因为我希望在滚动过程中包含的 Web 视图上方有标签(请参见屏幕截图)。

那么,如何让 webview 自行调整大小,以便占用显示其包含的内容所需的所有空间?

然后,如何让超级视图(滚动视图)根据 webview 的大小调整自身大小?

【问题讨论】:

    标签: ios swift uiwebview autolayout


    【解决方案1】:

    要完成这项工作,您必须执行以下步骤:

    1. 将UIWebView 从笔尖连接到视图控制器中的插座
    2. 在 Web 视图中禁用滚动
    3. 在UIScrollView、Web 视图顶部的UIView 上设置约束(在我的示例中,我省略了该视图中的所有标签)和UIWebView。
    4. 将 UIWebView 的 height 约束连接到视图控制器中的插座。
    5. 将视图控制器设置为UIWebViewDelegate
    6. 在webViewDidFinishLoad 中,将高度约束的常量设置为Web 视图内滚动视图的contentSize 的高度。
    7. 在 contentSize 上启动 Key-Value Observing 以更改高度,当 Web 视图的高度必须更改时,因为网页的各个部分在不重新加载页面的情况下更改其大小(如手风琴或菜单)。

    我不会详细解释这些限制,因为您似乎已经自己弄清楚了。这是约束的屏幕截图:

    所以,这里是代码:

    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()
            }
        }
    }
    

    【讨论】:

    • 嘿!当您最初发布它时,我看到了您的答案,但决定在我处理我的应用程序的第二个版本时解决问题。非常感谢,我只是尝试修复所有问题,并且效果很好。我只需要修复一些约束值来垂直偏移滚动视图(因为我在顶部也有一个导航栏,它不完全是一个空的超级视图)。这是我第一次将代码与观察者一起使用,所以稍后我将不得不更仔细地查看它,但现在,它可以工作了!谢谢
    • 感谢您的反馈,很高兴它对您有所帮助。
    • 嗨,乔恩,很好的答案。我很好奇为什么 MyObservationContext 在这个例子中是全局的。它似乎也可以作为类级别变量正常工作。你能给我一些启示吗?谢谢。 +1
    • 嗨,丹。你是对的,它应该是一个类属性。没有理由让它全球化。感谢您的评论!
    • 我观察到这是非常不准确的。当我每次调用webViewDidFinishLoad 时更新约束时,我最终得到的结果不会超过屏幕上的内容。如果我只在最后一次通话 (webView.isLoading == false) 上这样做,我几乎可以看到整页,但最后会被切断。
    【解决方案2】:

    来自@joern 的出色解决方案。对我来说很好。我刚刚将他的代码修改为 swift 3。

    Swift 3 更新代码:

    我还修改了 stopObservingHeight 以防止在创建之前删除观察者。

    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.isScrollEnabled = 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() {
            if observing {
                webView.scrollView.removeObserver(self, forKeyPath: "contentSize", context: &MyObservationContext)            
                observing = false
            }
        }
    
        override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
            guard let keyPath = keyPath,
                let context = context else {
                super.observeValue(forKeyPath: nil, of: object, change: change, context: nil)
                return
            }
            switch (keyPath, context) {
            case("contentSize", &MyObservationContext):
                webviewHeightConstraint.constant = webview.scrollView.contentSize.height
            default:
                super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
            }
        }
    }
    
    extension ViewController: UIWebViewDelegate {
        func webViewDidFinishLoad(_ webView: UIWebView) {
            print(webView.request?.url ?? "nil")
            webviewHeightConstraint.constant = webview.scrollView.contentSize.height
            if (!observing) {
                startObservingHeight()
            }
        }
    }
    

    【讨论】:

    • 将let context = context 添加到guard 将解决case("contentSize", &amp;MyObservationContext): 中的错误。很棒的更新!
    猜你喜欢
    • 2021-08-28
    • 1970-01-01
    • 2021-01-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多