-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathKeyboardAvoidingView.swift
103 lines (85 loc) · 3.76 KB
/
KeyboardAvoidingView.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
import ExpoModulesCore
// This view will be used as a native component. Make sure to inherit from `ExpoView`
// to apply the proper styling (e.g. border radius and shadows).
class KeyboardAvoidingView: ExpoView, ViewBoundsObserving {
private let measurer = BoundsObservableView()
private let container = UIView()
private var scrollViewComponent: ScrollViewComponentWrapper?
required init(appContext: AppContext? = nil) {
super.init(appContext: appContext)
clipsToBounds = true
measurer.translatesAutoresizingMaskIntoConstraints = false
measurer.isHidden = true
measurer.delegate = self
addSubview(measurer)
container.translatesAutoresizingMaskIntoConstraints = false
addSubview(container)
NSLayoutConstraint.activate([
measurer.leadingAnchor.constraint(equalTo: leadingAnchor),
measurer.trailingAnchor.constraint(equalTo: trailingAnchor),
measurer.bottomAnchor.constraint(equalTo: bottomAnchor),
])
NSLayoutConstraint.activate([
container.heightAnchor.constraint(equalTo: heightAnchor),
container.leadingAnchor.constraint(equalTo: leadingAnchor),
container.trailingAnchor.constraint(equalTo: trailingAnchor),
])
let measurerTopToKeyboard = measurer.topAnchor.constraint(
equalTo: keyboardLayoutGuide.topAnchor)
measurerTopToKeyboard.identifier = "measurerTopToKeyboard"
let containerBottomToKeyboard = container.bottomAnchor.constraint(
equalTo: keyboardLayoutGuide.topAnchor)
containerBottomToKeyboard.identifier = "containerBottomToKeyboard"
keyboardLayoutGuide.setConstraints(
[measurerTopToKeyboard, containerBottomToKeyboard], activeWhenNearEdge: .bottom)
let measurerTopToBottom = measurer.topAnchor.constraint(equalTo: bottomAnchor)
measurerTopToBottom.identifier = "measurerTopToKeyboard"
let containerBottomToBottom = container.bottomAnchor.constraint(equalTo: bottomAnchor)
containerBottomToBottom.identifier = "containerBottomToKeyboard"
keyboardLayoutGuide.setConstraints(
[measurerTopToBottom, containerBottomToBottom], activeWhenAwayFrom: .bottom)
keyboardLayoutGuide.followsUndockedKeyboard = true
if #available(iOS 17.0, *) {
keyboardLayoutGuide.usesBottomSafeArea = false
}
}
func boundsDidChange(_ view: BoundsObservableView, from previousBounds: CGRect) {
self.scrollViewComponent?.setInsetsFromKeyboardHeight(view.bounds.height, updateOffset: false)
}
#if RCT_NEW_ARCH_ENABLED
override func mountChildComponentView(_ childComponentView: UIView, index: Int) {
// FIXME: Use a nativeID to find the ScrollView
if index == 0 {
scrollViewComponent = ScrollViewComponentWrapper(view: childComponentView)
scrollViewComponent?.setInsetsFromKeyboardHeight(measurer.bounds.height, updateOffset: true)
}
container.insertSubview(childComponentView, at: index)
}
override func unmountChildComponentView(_ childComponentView: UIView, index: Int) {
if childComponentView === scrollViewComponent?.view {
scrollViewComponent = nil
}
childComponentView.removeFromSuperview()
}
#else
override func insertReactSubview(_ subview: UIView!, at index: Int) {
super.insertReactSubview(subview, at: index)
// FIXME: Use a nativeID to find the ScrollView
if index == 0 {
scrollViewComponent = ScrollViewComponentWrapper(view: subview)
scrollViewComponent?.setInsetsFromKeyboardHeight(measurer.bounds.height, updateOffset: true)
}
container.insertSubview(subview, at: index)
}
override func removeReactSubview(_ subview: UIView!) {
super.removeReactSubview(subview)
if subview === scrollViewComponent?.view {
scrollViewComponent = nil
}
subview.removeFromSuperview()
}
override func didUpdateReactSubviews() {
// no-op
}
#endif
}