Skip to content

Commit 6d76a75

Browse files
authored
fixed for ios 13 toolbar issue. and moved out some code to a new file. (#9)
* fixed for ios 13 toolbar issue. and moved out some code to a new file. * moved extensions under Sources folder * fixed bottom constraint.
1 parent 2b3b8f0 commit 6d76a75

File tree

3 files changed

+169
-113
lines changed

3 files changed

+169
-113
lines changed

MHWebViewController/Sources/MHWebViewController.swift

Lines changed: 86 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,28 @@ import WebKit
1111

1212
public class MHWebViewController:UIViewController {
1313

14-
public private(set) lazy var webView:WKWebView = WKWebView(frame: CGRect.zero)
14+
enum WebViewKeyPath:String {
15+
case estimatedProgress
16+
case title
17+
}
1518

16-
private lazy var toolbar:UIToolbar = UIToolbar(frame: CGRect.zero)
1719
private lazy var container = UIView(frame: CGRect.zero)
18-
private lazy var progressView = UIProgressView(progressViewStyle: .default)
20+
private lazy var progressView = UIProgressView(progressViewStyle: .bar)
21+
public private(set) lazy var webView:WKWebView = WKWebView(frame: CGRect.zero)
22+
23+
private lazy var toolbar:UIView = {
24+
let v = UIView(frame: CGRect.zero)
25+
v.isUserInteractionEnabled = true
26+
v.heightAnchor.constraint(equalToConstant: 44.0).isActive = true
27+
v.translatesAutoresizingMaskIntoConstraints = false
28+
29+
let blurEffect = UIBlurEffect(style: .light)
30+
let blurEffectView = UIVisualEffectView(effect: blurEffect)
31+
v.addSubview(blurEffectView)
32+
blurEffectView.bindFrameToSuperviewBounds()
33+
return v
34+
}()
35+
1936
private lazy var titleLabel:UILabel = {
2037
let lbl = UILabel(frame: CGRect(x: 0.0, y: 0.0, width: 250.0, height: 16.0))
2138
lbl.adjustsFontSizeToFitWidth = true
@@ -35,9 +52,7 @@ public class MHWebViewController:UIViewController {
3552
}()
3653

3754
private let topMargin:CGFloat = 10.0
38-
3955
private var lastLocation:CGPoint = .zero
40-
4156
public var request:URLRequest!
4257

4358
public override var title: String? {
@@ -56,94 +71,119 @@ public class MHWebViewController:UIViewController {
5671

5772
override public func loadView() {
5873
super.loadView()
74+
setupMainLayout()
75+
setupToolbar()
76+
}
77+
78+
override public func viewDidLoad() {
79+
super.viewDidLoad()
80+
addPanGestureRecognizer()
81+
titleLabel.text = titleHidden ? "" : NSLocalizedString(
82+
"Loading...", comment: "the loading text at the top")
83+
webView.navigationDelegate = self
84+
webView.load(request)
85+
}
86+
87+
public override func viewDidAppear(_ animated: Bool) {
88+
super.viewDidAppear(animated)
89+
addWebViewObservers()
90+
}
91+
92+
public override func viewDidDisappear(_ animated: Bool) {
93+
super.viewDidDisappear(animated)
94+
removeWebViewObservers()
95+
}
96+
97+
private func setupToolbar() {
98+
// toolbar
99+
let closeButton = createImageButton(imageName: "close_button")
100+
closeButton.addTarget(self, action: #selector(dismissMe(_:)), for: .touchUpInside)
101+
closeButton.tintColor = .gray
102+
closeButton.widthAnchor.constraint(equalTo: closeButton.heightAnchor).isActive = true
103+
104+
let titleStackView = UIStackView(arrangedSubviews: [titleLabel, urlLabel])
105+
titleStackView.axis = .vertical
106+
107+
let toolbarStackView = UIStackView(arrangedSubviews: [closeButton, titleStackView])
108+
toolbarStackView.spacing = 2.0
109+
toolbarStackView.axis = .horizontal
110+
toolbar.addSubview(toolbarStackView)
111+
112+
toolbarStackView.translatesAutoresizingMaskIntoConstraints = false
113+
toolbarStackView.topAnchor.constraint(equalTo: toolbar.topAnchor, constant: 5).isActive = true
114+
toolbarStackView.leadingAnchor.constraint(equalTo: toolbar.leadingAnchor, constant: 5).isActive = true
115+
toolbarStackView.bottomAnchor.constraint(equalTo: toolbar.bottomAnchor, constant: -5).isActive = true
116+
toolbarStackView.trailingAnchor.constraint(equalTo: toolbar.trailingAnchor, constant: -49).isActive = true
117+
}
118+
119+
private func createImageButton(imageName: String) -> UIButton {
120+
guard let closeImage = UIImage(
121+
named: imageName,
122+
in: Bundle(for: MHWebViewController.self),
123+
compatibleWith: nil) else { fatalError("No image named \(imageName) in the MHWebViewController.bundle") }
124+
let closeButton = UIButton(type: .custom)
125+
closeButton.setImage(closeImage, for: .normal)
126+
return closeButton
127+
}
128+
129+
private func setupMainLayout() {
59130
view = UIView()
60131
view.autoresizingMask = [.flexibleHeight, .flexibleWidth]
61-
view.backgroundColor = UIColor.clear
62-
63-
// Setup container
132+
view.backgroundColor = .clear
64133
view.addSubview(container)
65134
container.translatesAutoresizingMaskIntoConstraints = false
66135
container.topAnchor.constraint(
67136
equalTo: view.safeTopAnchor, constant: topMargin).isActive = true
68-
container.heightAnchor.constraint(
69-
equalTo: view.heightAnchor, constant: -topMargin - 44.0).isActive = true
137+
container.bottomAnchor.constraint(
138+
equalTo: view.bottomAnchor).isActive = true
70139
container.leadingAnchor.constraint(
71140
equalTo: view.safeLeadingAnchor, constant: 0).isActive = true
72141
container.trailingAnchor.constraint(
73142
equalTo: view.safeTrailingtAnchor, constant: 0).isActive = true
74-
container.layer.cornerRadius = 10.0
143+
container.layer.cornerRadius = 16.0
75144
container.clipsToBounds = true
76-
77-
addPanGestureRecognizer()
78-
guard let closeImage = UIImage(
79-
named: "close_button",
80-
in: Bundle(for: MHWebViewController.self),
81-
compatibleWith: nil) else { return }
82145

83-
let closeButton = UIBarButtonItem(
84-
image: closeImage,
85-
style: .plain,
86-
target: self,
87-
action: #selector(dismissMe(_:)))
88-
closeButton.tintColor = UIColor.darkGray
89-
90-
let titleStackView = UIStackView(arrangedSubviews: [titleLabel, urlLabel])
91-
titleStackView.axis = .vertical
92-
let titleItem = UIBarButtonItem(customView: titleStackView)
93-
94-
let flexibleSpace = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: self, action: nil)
95-
toolbar.items = [closeButton, flexibleSpace, titleItem, flexibleSpace]
96-
97146
let mainStackView = UIStackView(arrangedSubviews: [toolbar, progressView, webView])
98147
mainStackView.axis = .vertical
99148
container.addSubview(mainStackView)
100149
mainStackView.bindFrameToSuperviewBounds()
101150
}
102151

103-
override public func viewDidLoad() {
104-
super.viewDidLoad()
105-
titleLabel.text = titleHidden ? "" : NSLocalizedString("LOADING...", comment: "the loading text at the top")
106-
webView.navigationDelegate = self
107-
webView.load(request)
108-
}
109-
110-
public override func viewDidAppear(_ animated: Bool) {
152+
private func addWebViewObservers() {
111153
webView.addObserver(self, forKeyPath: #keyPath(WKWebView.estimatedProgress), options: .new, context: nil)
112154
webView.addObserver(self, forKeyPath: #keyPath(WKWebView.title), options: .new, context: nil)
113155
webView.addObserver(self, forKeyPath: #keyPath(WKWebView.canGoBack), options: .new, context: nil)
114156
webView.addObserver(self, forKeyPath: #keyPath(WKWebView.canGoForward), options: .new, context: nil)
115157
}
116158

117-
public override func viewDidDisappear(_ animated: Bool) {
159+
private func removeWebViewObservers() {
118160
webView.removeObserver(self, forKeyPath: #keyPath(WKWebView.estimatedProgress))
119161
webView.removeObserver(self, forKeyPath: #keyPath(WKWebView.title))
120162
webView.removeObserver(self, forKeyPath: #keyPath(WKWebView.canGoBack))
121163
webView.removeObserver(self, forKeyPath: #keyPath(WKWebView.canGoForward))
122164
}
123165

124-
@objc private func dismissMe(_ sender: UIBarButtonItem) {
166+
@objc private func dismissMe(_ sender: UIButton) {
125167
dismiss(completion: nil)
126168
}
127169

128170
public func dismiss(completion: (() -> Void)? = nil) {
129171
dismiss(animated: true, completion: completion)
130172
}
131173

132-
override public func observeValue(
133-
forKeyPath keyPath: String?,
134-
of object: Any?,
174+
override public func observeValue(forKeyPath keyPath: String?, of object: Any?,
135175
change: [NSKeyValueChangeKey : Any]?,
136176
context: UnsafeMutableRawPointer?) {
137177

138178
switch keyPath {
139-
case "estimatedProgress":
179+
case WebViewKeyPath.estimatedProgress.rawValue:
140180
progressView.progress = Float(webView.estimatedProgress)
141181
if progressView.progress == 1.0 {
142182
progressView.alpha = 0.0
143183
} else if progressView.alpha != 1.0 {
144184
progressView.alpha = 1.0
145185
}
146-
case "title":
186+
case WebViewKeyPath.title.rawValue:
147187
title = titleHidden ? "" : webView.title
148188
if !titleHidden, let scheme = webView.url?.scheme,
149189
let host = webView.url?.host {
@@ -225,70 +265,3 @@ extension MHWebViewController:WKNavigationDelegate {
225265
decisionHandler(.allow)
226266
}
227267
}
228-
229-
public extension UIViewController {
230-
231-
// Shortcuts
232-
@objc
233-
func present(urlRequest: URLRequest, titleHidden:Bool = false, completion: (() -> Void)? = nil) {
234-
let web = MHWebViewController()
235-
web.request = urlRequest
236-
web.modalPresentationStyle = .overCurrentContext
237-
web.titleHidden = titleHidden
238-
present(web, animated: true, completion: completion)
239-
}
240-
241-
@objc
242-
func present(url: URL, titleHidden:Bool = false, completion: (() -> Void)? = nil) {
243-
let urlRequest = URLRequest(url: url)
244-
present(urlRequest: urlRequest, titleHidden: titleHidden, completion: completion)
245-
}
246-
}
247-
248-
fileprivate extension UIView {
249-
250-
var safeTopAnchor: NSLayoutYAxisAnchor {
251-
if #available(iOS 11.0, *) {
252-
return self.safeAreaLayoutGuide.topAnchor
253-
}
254-
return self.topAnchor
255-
}
256-
257-
var safeLeadingAnchor: NSLayoutXAxisAnchor {
258-
if #available(iOS 11.0, *){
259-
return self.safeAreaLayoutGuide.leadingAnchor
260-
}
261-
return self.leadingAnchor
262-
}
263-
264-
var safeTrailingtAnchor: NSLayoutXAxisAnchor {
265-
if #available(iOS 11.0, *){
266-
return self.safeAreaLayoutGuide.trailingAnchor
267-
}
268-
return self.trailingAnchor
269-
}
270-
271-
var safeBottomAnchor: NSLayoutYAxisAnchor {
272-
if #available(iOS 11.0, *) {
273-
return self.safeAreaLayoutGuide.bottomAnchor
274-
}
275-
return self.bottomAnchor
276-
}
277-
278-
func bindFrameToSuperviewBounds() {
279-
guard let superview = self.superview else {
280-
print("Error! `superview` was nil – call `addSubview(view: UIView)`")
281-
return
282-
}
283-
284-
self.translatesAutoresizingMaskIntoConstraints = false
285-
self.topAnchor.constraint(
286-
equalTo: superview.topAnchor, constant: 0).isActive = true
287-
self.bottomAnchor.constraint(
288-
equalTo: superview.bottomAnchor, constant: 0).isActive = true
289-
self.leadingAnchor.constraint(
290-
equalTo: superview.leadingAnchor, constant: 0).isActive = true
291-
self.trailingAnchor.constraint(
292-
equalTo: superview.trailingAnchor, constant: 0).isActive = true
293-
}
294-
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
//
2+
// UIViewController_Extensions.swift
3+
// MHWebViewController
4+
//
5+
// Created by Michael Henry Pantaleon on 2019/09/30.
6+
//
7+
8+
import UIKit
9+
10+
public extension UIViewController {
11+
12+
// Shortcuts
13+
@objc
14+
func present(urlRequest: URLRequest, titleHidden:Bool = false, completion: (() -> Void)? = nil) {
15+
let web = MHWebViewController()
16+
web.request = urlRequest
17+
web.modalPresentationStyle = .overCurrentContext
18+
web.titleHidden = titleHidden
19+
present(web, animated: true, completion: completion)
20+
}
21+
22+
@objc
23+
func present(url: URL, titleHidden:Bool = false, completion: (() -> Void)? = nil) {
24+
let urlRequest = URLRequest(url: url)
25+
present(urlRequest: urlRequest, titleHidden: titleHidden, completion: completion)
26+
}
27+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
//
2+
// UView_Extensions.swift
3+
// MHWebViewController
4+
//
5+
// Created by Michael Henry Pantaleon on 2019/09/30.
6+
//
7+
8+
import UIKit
9+
10+
extension UIView {
11+
12+
var safeTopAnchor: NSLayoutYAxisAnchor {
13+
if #available(iOS 11.0, *) {
14+
return self.safeAreaLayoutGuide.topAnchor
15+
}
16+
return self.topAnchor
17+
}
18+
19+
var safeLeadingAnchor: NSLayoutXAxisAnchor {
20+
if #available(iOS 11.0, *){
21+
return self.safeAreaLayoutGuide.leadingAnchor
22+
}
23+
return self.leadingAnchor
24+
}
25+
26+
var safeTrailingtAnchor: NSLayoutXAxisAnchor {
27+
if #available(iOS 11.0, *){
28+
return self.safeAreaLayoutGuide.trailingAnchor
29+
}
30+
return self.trailingAnchor
31+
}
32+
33+
var safeBottomAnchor: NSLayoutYAxisAnchor {
34+
if #available(iOS 11.0, *) {
35+
return self.safeAreaLayoutGuide.bottomAnchor
36+
}
37+
return self.bottomAnchor
38+
}
39+
40+
func bindFrameToSuperviewBounds() {
41+
guard let superview = self.superview else {
42+
print("Error! `superview` was nil – call `addSubview(view: UIView)`")
43+
return
44+
}
45+
46+
self.translatesAutoresizingMaskIntoConstraints = false
47+
self.topAnchor.constraint(
48+
equalTo: superview.topAnchor, constant: 0).isActive = true
49+
self.bottomAnchor.constraint(
50+
equalTo: superview.bottomAnchor, constant: 0).isActive = true
51+
self.leadingAnchor.constraint(
52+
equalTo: superview.leadingAnchor, constant: 0).isActive = true
53+
self.trailingAnchor.constraint(
54+
equalTo: superview.trailingAnchor, constant: 0).isActive = true
55+
}
56+
}

0 commit comments

Comments
 (0)