Skip to content

Commit 965e4bc

Browse files
authored
Merge pull request #1 from freshOS/refactor
UIView extension
2 parents 7e24ef4 + f3cafd1 commit 965e4bc

File tree

2 files changed

+43
-43
lines changed

2 files changed

+43
-43
lines changed

KeyboardLayoutGuide/KeyboardLayoutGuide/Keyboard+LayoutGuide.swift

Lines changed: 41 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,29 @@
88

99
import UIKit
1010

11-
12-
public class KeyboardLayoutGuide: UILayoutGuide {
11+
public extension UIView {
1312

14-
private var token: NSKeyValueObservation? = nil
13+
private struct AssociatedKeys {
14+
static var keyboardLayoutGuide = "keyboardLayoutGuide"
15+
}
16+
17+
/// A layout guide representing the inset for the keyboard.
18+
/// Use this layout guide’s top anchor to create constraints pinning to the top of the keyboard.
19+
public var keyboardLayoutGuide: KeyboardLayoutGuide {
20+
get {
21+
if let obj = objc_getAssociatedObject(self, &AssociatedKeys.keyboardLayoutGuide) as? KeyboardLayoutGuide {
22+
return obj
23+
}
24+
let new = KeyboardLayoutGuide()
25+
addLayoutGuide(new)
26+
new.setUp()
27+
objc_setAssociatedObject(self, &AssociatedKeys.keyboardLayoutGuide, new as Any, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
28+
return new
29+
}
30+
}
31+
}
32+
33+
open class KeyboardLayoutGuide: UILayoutGuide {
1534

1635
public required init?(coder aDecoder: NSCoder) {
1736
fatalError("init(coder:) has not been implemented")
@@ -20,31 +39,24 @@ public class KeyboardLayoutGuide: UILayoutGuide {
2039
public override init() {
2140
super.init()
2241

23-
// Observe keyboardWillShow and keyboardWillHide notifications.
42+
// Observe keyboardWillChangeFrame notifications
2443
let nc = NotificationCenter.default
2544
nc.addObserver(self,
26-
selector: #selector(keyboardWillShow(_:)),
27-
name: .UIKeyboardWillShow,
45+
selector: #selector(keyboardWillChangeFrame(_:)),
46+
name: .UIKeyboardWillChangeFrame,
2847
object: nil)
29-
nc.addObserver(self,
30-
selector: #selector(keyboardWillHide(_:)),
31-
name: .UIKeyboardWillHide,
32-
object: nil)
33-
34-
// Observe owningView so that we can setup our layoutGuide
35-
// once the user has called `view.addLayoutGuide`
36-
token = observe(\.owningView) { object, _ in
37-
if let view = object.owningView {
38-
object.setUp(inView: view)
39-
}
40-
}
4148
}
4249

43-
private func setUp(inView view: UIView) {
44-
heightAnchor.constraint(equalToConstant: 0).isActive = true
45-
leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
46-
rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
47-
let viewBottomAnchor: NSLayoutYAxisAnchor!
50+
internal func setUp() {
51+
guard let view = owningView else {
52+
return
53+
}
54+
NSLayoutConstraint.activate([
55+
heightAnchor.constraint(equalToConstant: 0),
56+
leftAnchor.constraint(equalTo: view.leftAnchor),
57+
rightAnchor.constraint(equalTo: view.rightAnchor),
58+
])
59+
let viewBottomAnchor: NSLayoutYAxisAnchor
4860
if #available(iOS 11.0, *) {
4961
viewBottomAnchor = view.safeAreaLayoutGuide.bottomAnchor
5062
} else {
@@ -54,22 +66,16 @@ public class KeyboardLayoutGuide: UILayoutGuide {
5466
}
5567

5668
@objc
57-
func keyboardWillShow(_ note: Notification) {
69+
private func keyboardWillChangeFrame(_ note: Notification) {
5870
if var height = note.keyboardHeight {
59-
if #available(iOS 11.0, *) {
71+
if #available(iOS 11.0, *), height > 0 {
6072
height -= (owningView?.safeAreaInsets.bottom)!
6173
}
6274
heightConstraint?.constant = height
6375
animate(note)
6476
}
6577
}
6678

67-
@objc
68-
func keyboardWillHide(_ note: Notification) {
69-
heightConstraint?.constant = 0
70-
animate(note)
71-
}
72-
7379
private func animate(_ note: Notification) {
7480
if isVisible(view: self.owningView!) {
7581
self.owningView?.layoutIfNeeded()
@@ -88,7 +94,7 @@ public class KeyboardLayoutGuide: UILayoutGuide {
8894
// MARK: - Helpers
8995

9096
extension UILayoutGuide {
91-
var heightConstraint: NSLayoutConstraint? {
97+
internal var heightConstraint: NSLayoutConstraint? {
9298
guard let target = owningView else { return nil }
9399
for c in target.constraints {
94100
if let fi = c.firstItem as? UILayoutGuide, fi == self && c.firstAttribute == .height {
@@ -104,7 +110,9 @@ extension Notification {
104110
guard let v = userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue else {
105111
return nil
106112
}
107-
return v.cgRectValue.size.height
113+
// Weirdly enough UIKeyboardFrameEndUserInfoKey doesn't have the same behaviour
114+
// in ios 10 or iOS 11 so we can't rely on v.cgRectValue.width
115+
return UIScreen.main.bounds.height - v.cgRectValue.minY
108116
}
109117
}
110118

KeyboardLayoutGuideExample/KeyboardLayoutGuideExample/ViewController.swift

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,21 +10,13 @@ import UIKit
1010
import KeyboardLayoutGuide
1111

1212
class ViewController: UIViewController {
13-
14-
// Create a keyboard layout guide.
15-
let keyboardLayoutGuide = KeyboardLayoutGuide()
1613

1714
@IBOutlet weak var button: UIButton!
1815

1916
override func viewDidLoad() {
2017
super.viewDidLoad()
2118

22-
// Add the layout guide in the view.
23-
view.addLayoutGuide(keyboardLayoutGuide)
24-
25-
// Constrain your button to the keyboardLayoutGuide's top Anchor
26-
// the way you would do natively :)
27-
button.bottomAnchor.constraint(equalTo: keyboardLayoutGuide.topAnchor).isActive = true
19+
// Constrain your button to the keyboardLayoutGuide's top Anchor the way you would do natively :)
20+
button.bottomAnchor.constraint(equalTo: view.keyboardLayoutGuide.topAnchor).isActive = true
2821
}
2922
}
30-

0 commit comments

Comments
 (0)