IOS 23 实现通用WebView控制器(WKWebView)

在项目中我们经常会在多个界面使用到WebView,所以本文对WebView进行封装,实现一个通用的WebView控制器。

实现效果

简单的Webview

实现逻辑

使用系统提供的WKWebView控件,外界通过传递网址,或者字符串进行显示。

1)创建WebView控制器SuperWebController,继承自BaseTitleController。

class SuperWebController: BaseTitleController {
}

2)定义SuperWebController接收的两个参数uri和content。

class SuperWebController: BaseTitleController {
    var uri:String?
    var content:String?
}

3)重写initViews(),设置SuperWebController内容布局为RelativeLayout,并添加标题栏右边的关闭按钮 和 webView控件,webView控件使用懒加载创建。

class SuperWebController: BaseTitleController {
    var uri:String?
    var content:String?

    override func initViews() {
        super.initViews()
        initRelativeLayoutSafeArea()

        //设置右侧按钮
        addRightImageButton(R.image.close()!.withTintColor())

        container.addSubview(webView)
    }

    /// 获取配置
    static func defaultConfiguration() -> WKWebViewConfiguration {
        let r = WKWebViewConfiguration()
        if #available(iOS 10.0, *) {
            r.mediaTypesRequiringUserActionForPlayback = .all
        } else if #available(iOS 9.0, *){
            r.requiresUserActionForMediaPlayback = false
        }else{
            r.mediaPlaybackRequiresUserAction = false
        }
        return r
    }

    lazy var webView: WKWebView = {
        let r = WKWebView(frame: CGRect.zero, configuration: SuperWebController.defaultConfiguration())
        r.tg_width.equal(.fill)
        r.tg_height.equal(.fill)
        return r
    }()
}

4)获取外界传入的数据,并设置到webview上。

class SuperWebController: BaseTitleController {

    static let CONTENT_WRAPPER_START = "<!DOCTYPE html><html><head><title></title><meta name=\"viewport\" content=\"width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no\"><style type=\"text/css\"> body{font-family: Helvetica Neue,Helvetica,PingFang SC,Hiragino Sans GB,Microsoft YaHei,Arial,sans-serif;word-wrap: break-word;word-break: normal;} h2{text-align: center;} img {max-width: 100%;} pre{word-wrap: break-word!important;overflow: auto;}</style></head><body>"

    static let CONTENT_WRAPPER_END = "</body></html>"

    static let WEBVIEW_BASE_URL = "http://ixuea.com"

    override func initDatum() {
        super.initDatum()
        if SuperStringUtil.isNotBlank(uri) {
            //显示网址内容
            //创建一个Request
            let request = URLRequest(url: URL(string: uri)!)

            //请求
            webView.load(request)
        } else {
            //显示字符串

            //由于服务端,返回的字符串,不是一个完整的HTML字符串
            //同时本地可能希望添加一些字体设置,所以要前后拼接为一个
            //完整的HTML字符串
            var buffer = String(SuperWebController.CONTENT_WRAPPER_START)

            //添加内容
            buffer.append(content!)

            buffer.append(SuperWebController.CONTENT_WRAPPER_END)

            //加载字符串
            webView.loadHTMLString(buffer, baseURL: URL(string: SuperWebController.WEBVIEW_BASE_URL))
        }
    }
}

5)拦截返回按钮事件和添加关闭页面事件

class SuperWebController: BaseTitleController {
    
    /// 拦截点击返回按钮
    override func leftClick(_ sender: QMUIButton) {
        if webView.canGoBack {
            //如果浏览器能返回上一页,就直接返回上一页
            webView.goBack()
            return
        }

        super.leftClick(sender)
    }

    override func rightClick(_ sender: QMUIButton) {
        finish()
    }

    /// 关闭界面
    func finish() {
        navigationController?.popViewController(animated: true)
    }
}

6)扩展一个start方法,提供给外界启动webview。

extension SuperWebController{

    /// 启动方法
    static func start(_ controller:UINavigationController,title:String?=nil,uri:String?=nil,content:String?=nil) {
        let target = SuperWebController()
        target.title = title
        target.uri=uri
        target.content = content
        controller.pushViewController(target, animated: true)
    }
}

7)使用webview

SuperWebController.start(navigationController!,title: data.title,uri: data.uri)

至此,简单的webview就实现了,下面继续封装 动态网页标题和进度功能。

动态标题和进度Webview

实现逻辑

如果外界没有传递标题,就显示网页标题;仿微信内部的浏览器顶部的进度条,这里要实现类似功能。进度条控件使用UIProgressView,然后监听webView进度,并设置到进度条。

1)给SuperWebController添加UIProgressView,UIProgressView控件使用懒加载创建。

class SuperWebController : BaseTitleController{
    
    override func initViews() {
        super.initViews()
        initRelativeLayoutSafeArea()
        
        //设置右侧按钮
        addRightImageButton(R.image.close()!.withTintColor())
        
        container.addSubview(webView)
        
        container.addSubview(progressView)
    }

    lazy var progressView: UIProgressView = {
        let r = UIProgressView()
        r.tg_width.equal(.fill)
        r.tg_height.equal(1)
        
        //设置进度条的颜色
        r.progressTintColor = .colorPrimary
        return r
    }()
}

2)添加标题和进度监听

class SuperWebController : BaseTitleController{
    
    override func initListeners() {
        super.initListeners()
        if SuperStringUtil.isBlank(title){
            //监听网页标题
            webView.addObserver(self, forKeyPath: "title", options: .new,context: nil)
        }
        
        //监听加载进度
        webView.addObserver(self, forKeyPath: "estimatedProgress", options: .new, context: nil)
    }

}

3)重写KVO监听回调,动态更新标题和进度条。

class SuperWebController : BaseTitleController{

    /// KVO监听回调
    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        if let _ = object as? WKWebView{
            if keyPath == "title"{
                //标题
                title = webView.title
            }else if keyPath == "estimatedProgress"{
                //进度
                
                //0~1
                let progress = change?[.newKey] as? Float ?? 0
                progressView.progress = progress
                
                if progress < 1 {
                    progressView.show()
                    
                    //完全不透明
                    progressView.alpha = 1
                }else{
                    UIView.animate(withDuration: 0.35, delay: 0.15) {
                        self.progressView.alpha = 0
                    } completion: { finished in
                        if finished {
                            self.progressView.hide()
                            self.progressView.progress=0
                            self.progressView.alpha = 1
                        }
                    }

                }
            }
        }
    }
    
}

至此,动态网页标题和进度功能的webview就实现了。

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

sziitjin

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值