在项目中我们经常会在多个界面使用到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就实现了。
版权归原作者 sziitjin 所有, 如有侵权,请联系我们删除。