【iOS开发】WKWebView遇上UIScrollView,动态获取WKWebView的高度

开发过程中经常会碰到这样的需求,顶部是自定义的UIView,下面是使用webView,然后实现一起滚动。需求如下图:

[图片上传失败...(image-49b65c-1531367583533)]

实现思路也简单,可以使用UIScrollView为父视图,自定义view和webView作为子视图,或者使用UITableView,自定义view作为tableHeaderView,webView添加到UITableViewCell上。关键是如何获取高度。这里通过监听webView的contentSize的变化来获取高度,然后更新webView的高度,进而更新UIScrollView的可滚动区域实现滚动。


image.png

具体demo实现,实现方式采用UIScrollView + Snapkit布局

import UIKit
import SnapKit
import WebKit
 
class ViewController: UIViewController {
    
    lazy var webView: WKWebView = {
        let web = WKWebView()
        web.navigationDelegate = self
        web.scrollView.isScrollEnabled = false
        web.scrollView.bounces = false
        return web
    }()
    lazy var scrollView: UIScrollView = {
        let scroll = UIScrollView()
        return scroll
    }()
    lazy var contentView: UIView = {
        return UIView()
    }()
    lazy var customView: UILabel = {
        let label = UILabel()
        label.numberOfLines = 0
        label.backgroundColor = UIColor.gray
        return label
    }()
    var observing = false
 
    override func viewDidLoad() {
        super.viewDidLoad()
        addSubViews()
        addConstraints()
        loadWebView()
    }
    
    func addSubViews() {
        view.addSubview(scrollView)
        scrollView.addSubview(contentView)
        contentView.addSubview(customView)
        contentView.addSubview(webView)
    }
    
    func addConstraints() {
        scrollView.snp.makeConstraints { (make) in
            make.left.right.top.bottom.equalToSuperview()
        }
        contentView.snp.makeConstraints { (make) in
            make.top.bottom.equalToSuperview()
            make.left.right.equalTo(view)
        }
        customView.snp.makeConstraints { (make) in
            make.left.right.top.equalToSuperview().inset(20)
        }
        webView.snp.makeConstraints { (make) in
            make.left.right.equalToSuperview().inset(20)
            make.top.equalTo(customView.snp.bottom).offset(20)
            make.height.equalTo(400)
            make.bottom.equalToSuperview().offset(-20) // 需要设置距离底部的约束,否则无法计算contentSize
        }
    }
    
    func addWebViewObserver() {
        observing = true
        webView.scrollView.addObserver(self, forKeyPath: "contentSize", options: .new, context: nil)
    }
    
    func removeWebViewObserver() {
        webView.scrollView.removeObserver(self, forKeyPath: "contentSize", context: nil)
        observing = false
    }
    
    func loadWebView() {
        customView.text = "在强者的眼中,没有最好,只有更好。盆景秀木正因为被人溺爱,才破灭了成为栋梁之材的梦。永远都不要放弃自己,勇往直前,直至成功!没有平日的失败,就没有最终的成功。重要的是分析失败原因并吸取教训。蝴蝶如要在百花园里得到飞舞的欢乐,那首先得忍受与蛹决裂的痛苦。萤火虫的光点虽然微弱,但亮着便是向黑暗挑战。面对人生旅途中的挫折与磨难,我们不仅要有勇气,更要有坚强的信念。对坚强的人来说,不幸就像铁犁一样开垦着他内心的大地,虽然痛,却可以播种。想而奋进的过程,其意义远大于未知的结果。"
        
        webView.load(URLRequest(url: URL(string: "https://www.baidu.com/")!))
    }
    
    func updateWebViewHeight(_ height: CGFloat) {
        webView.snp.updateConstraints { (make) in
            make.height.equalTo(height)
        }
    }
    
    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        guard let keyPath = keyPath else {
            super.observeValue(forKeyPath: nil, of: object, change: change, context: context)
            return
        }
        if keyPath == "contentSize" {
            updateWebViewHeight(webView.scrollView.contentSize.height)
        }
    }
    
    deinit {
       removeWebViewObserver()
    }
}
 
extension ViewController: WKNavigationDelegate {
    // 网页加载完成,开始监听内容高度变化,不断更新高度,增大滚动区域
    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
        updateWebViewHeight(webView.scrollView.contentSize.height)
        if (!observing) { addWebViewObserver() }
    }

    func webView(_ webView: WKWebView, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
        let cred = URLCredential.init(trust: challenge.protectionSpace.serverTrust!)
        completionHandler(.useCredential, cred)
    }
}

代码简单,关键是注意几点:

1)通过添加容器视图contentView为scrollView自动计算滚动区域,不熟悉的可以看我前面一篇文章。

2)在网页加载吃完之后开始监听contentSize的变化,并不断更新webView的高度。这里会监听到contentSize不断的变化,因为内容在不断的加载,所以值也在不断变化,而且很多相同的值。自己可以对相同的值进行过滤操作,减少不必要的操作。如下部分高度值:

1908.0

1908.0

1908.0

1908.0

1908.0

1908.0

1908.0

1908.0

1908.0

1908.0

1908.0

1908.0

4272.0

4272.0

4272.0

4272.0

4272.0

...

3)实际的开发过程中,往往有可能是先加载本地的html,或者服务端给的一段html内容,然后请求数据,再向html中插入内容。在这种情况下,有时候最终的显示的滚动视图可能是对的,滚动到底部能够看到所有的内容,但是有时候也可能出现滚动的区域大于有效的显示内容。即所有内容看完之后还会存在一部分高度导致空白部分。会出现这种情况是因为加载的内容包含了图片,由于图片的加载和显示问题,当图片的大小和实际显示的大小显示不一致,导致了webView再监听contentSize的时候,出现了最大的contentSize之后,对于小的contentSize我们将获取不到,从而没有更新webView的高度,导致部分空白现象。这种情况可以跟前端讨论,处理图片的加载流程,保证高度内容一步一步增大。这样,我们就能够监听到正确的高度并显示。

实现效果图如下:

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343