react-native-keyboard-controller 1.18.3 → 1.18.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/android/src/main/java/com/reactnativekeyboardcontroller/modules/statusbar/StatusBarManagerCompatModuleImpl.kt +2 -3
- package/android/src/main/java/com/reactnativekeyboardcontroller/views/EdgeToEdgeReactViewGroup.kt +12 -5
- package/android/src/main/jni/CMakeLists.txt +14 -10
- package/ios/KeyboardControllerModule.mm +0 -1
- package/ios/observers/{KeyboardTrackingView.swift → movement/KeyboardTrackingView.swift} +17 -10
- package/ios/observers/movement/observer/KeyboardMovementObserver+Animation.swift +21 -0
- package/ios/observers/movement/observer/KeyboardMovementObserver+Interactive.swift +56 -0
- package/ios/observers/movement/observer/KeyboardMovementObserver+Lifecycle.swift +47 -0
- package/ios/observers/movement/observer/KeyboardMovementObserver+Listeners.swift +88 -0
- package/ios/observers/movement/observer/KeyboardMovementObserver+Watcher.swift +72 -0
- package/ios/observers/movement/observer/KeyboardMovementObserver.swift +63 -0
- package/ios/views/KeyboardExtenderContainerView.swift +24 -20
- package/lib/commonjs/components/KeyboardAvoidingView/index.js +6 -4
- package/lib/commonjs/components/KeyboardAvoidingView/index.js.map +1 -1
- package/lib/module/components/KeyboardAvoidingView/index.js +6 -4
- package/lib/module/components/KeyboardAvoidingView/index.js.map +1 -1
- package/package.json +1 -1
- package/src/components/KeyboardAvoidingView/index.tsx +7 -4
- package/ios/observers/KeyboardMovementObserver.swift +0 -307
- /package/ios/observers/{KeyboardEventsIgnorer.swift → movement/KeyboardEventsIgnorer.swift} +0 -0
- /package/ios/observers/{KeyboardViewLocator.swift → movement/KeyboardViewLocator.swift} +0 -0
|
@@ -9,9 +9,9 @@ import androidx.core.view.WindowInsetsCompat
|
|
|
9
9
|
import androidx.core.view.WindowInsetsControllerCompat
|
|
10
10
|
import com.facebook.react.bridge.ReactApplicationContext
|
|
11
11
|
import com.facebook.react.bridge.UiThreadUtil
|
|
12
|
-
import com.reactnativekeyboardcontroller.extensions.rootView
|
|
13
12
|
import com.reactnativekeyboardcontroller.log.Logger
|
|
14
13
|
import com.reactnativekeyboardcontroller.views.EdgeToEdgeReactViewGroup
|
|
14
|
+
import com.reactnativekeyboardcontroller.views.EdgeToEdgeViewRegistry
|
|
15
15
|
import java.lang.ref.WeakReference
|
|
16
16
|
|
|
17
17
|
private val TAG = StatusBarManagerCompatModuleImpl::class.qualifiedName
|
|
@@ -117,8 +117,7 @@ class StatusBarManagerCompatModuleImpl(
|
|
|
117
117
|
|
|
118
118
|
private fun isEnabled(): Boolean = view()?.active ?: false
|
|
119
119
|
|
|
120
|
-
private fun view(): EdgeToEdgeReactViewGroup? =
|
|
121
|
-
mReactContext.rootView?.findViewWithTag<EdgeToEdgeReactViewGroup>(EdgeToEdgeReactViewGroup.VIEW_TAG)
|
|
120
|
+
private fun view(): EdgeToEdgeReactViewGroup? = EdgeToEdgeViewRegistry.get()
|
|
122
121
|
|
|
123
122
|
companion object {
|
|
124
123
|
const val NAME = "StatusBarManager"
|
package/android/src/main/java/com/reactnativekeyboardcontroller/views/EdgeToEdgeReactViewGroup.kt
CHANGED
|
@@ -19,9 +19,20 @@ import com.reactnativekeyboardcontroller.listeners.KeyboardAnimationCallback
|
|
|
19
19
|
import com.reactnativekeyboardcontroller.listeners.KeyboardAnimationCallbackConfig
|
|
20
20
|
import com.reactnativekeyboardcontroller.log.Logger
|
|
21
21
|
import com.reactnativekeyboardcontroller.modal.ModalAttachedWatcher
|
|
22
|
+
import java.lang.ref.WeakReference
|
|
22
23
|
|
|
23
24
|
private val TAG = EdgeToEdgeReactViewGroup::class.qualifiedName
|
|
24
25
|
|
|
26
|
+
object EdgeToEdgeViewRegistry {
|
|
27
|
+
private var lastCreatedView: WeakReference<EdgeToEdgeReactViewGroup>? = null
|
|
28
|
+
|
|
29
|
+
fun register(view: EdgeToEdgeReactViewGroup) {
|
|
30
|
+
lastCreatedView = WeakReference(view)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
fun get(): EdgeToEdgeReactViewGroup? = lastCreatedView?.get()
|
|
34
|
+
}
|
|
35
|
+
|
|
25
36
|
@Suppress("detekt:TooManyFunctions")
|
|
26
37
|
@SuppressLint("ViewConstructor")
|
|
27
38
|
class EdgeToEdgeReactViewGroup(
|
|
@@ -58,7 +69,7 @@ class EdgeToEdgeReactViewGroup(
|
|
|
58
69
|
private val modalAttachedWatcher = ModalAttachedWatcher(this, reactContext, config, ::getKeyboardCallback)
|
|
59
70
|
|
|
60
71
|
init {
|
|
61
|
-
|
|
72
|
+
EdgeToEdgeViewRegistry.register(this)
|
|
62
73
|
}
|
|
63
74
|
|
|
64
75
|
// region View life cycles
|
|
@@ -241,8 +252,4 @@ class EdgeToEdgeReactViewGroup(
|
|
|
241
252
|
}
|
|
242
253
|
}
|
|
243
254
|
// endregion
|
|
244
|
-
|
|
245
|
-
companion object {
|
|
246
|
-
val VIEW_TAG = EdgeToEdgeReactViewGroup::class.simpleName
|
|
247
|
-
}
|
|
248
255
|
}
|
|
@@ -68,18 +68,22 @@ else()
|
|
|
68
68
|
)
|
|
69
69
|
endif()
|
|
70
70
|
|
|
71
|
-
|
|
72
|
-
${LIB_TARGET_NAME}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
71
|
+
if(ReactAndroid_VERSION_MINOR GREATER_EQUAL 80)
|
|
72
|
+
target_compile_reactnative_options(${LIB_TARGET_NAME} PRIVATE)
|
|
73
|
+
else()
|
|
74
|
+
target_compile_options(
|
|
75
|
+
${LIB_TARGET_NAME}
|
|
76
|
+
PRIVATE
|
|
77
|
+
-DLOG_TAG=\"ReactNative\"
|
|
78
|
+
-fexceptions
|
|
79
|
+
-frtti
|
|
80
|
+
-std=c++20
|
|
81
|
+
-Wall
|
|
82
|
+
)
|
|
83
|
+
endif()
|
|
80
84
|
|
|
81
85
|
target_include_directories(
|
|
82
86
|
${CMAKE_PROJECT_NAME}
|
|
83
87
|
PUBLIC
|
|
84
88
|
${CMAKE_CURRENT_SOURCE_DIR}
|
|
85
|
-
)
|
|
89
|
+
)
|
|
@@ -11,7 +11,6 @@
|
|
|
11
11
|
|
|
12
12
|
// Thanks to this guard, we won't import this header when we build for the old architecture.
|
|
13
13
|
#ifdef RCT_NEW_ARCH_ENABLED
|
|
14
|
-
#import <FBReactNativeSpec/FBReactNativeSpec.h>
|
|
15
14
|
#import <reactnativekeyboardcontroller/reactnativekeyboardcontroller.h>
|
|
16
15
|
#endif
|
|
17
16
|
|
|
@@ -66,16 +66,18 @@ final class KeyboardTrackingView: UIView {
|
|
|
66
66
|
|
|
67
67
|
translatesAutoresizingMaskIntoConstraints = false
|
|
68
68
|
|
|
69
|
-
if #available(iOS
|
|
70
|
-
|
|
69
|
+
if #available(iOS 15.0, *) {
|
|
70
|
+
if #available(iOS 17.0, *) {
|
|
71
|
+
rootView.keyboardLayoutGuide.usesBottomSafeArea = false
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
NSLayoutConstraint.activate([
|
|
75
|
+
leadingAnchor.constraint(equalTo: rootView.leadingAnchor, constant: 0),
|
|
76
|
+
trailingAnchor.constraint(equalTo: rootView.trailingAnchor, constant: 0),
|
|
77
|
+
bottomAnchor.constraint(equalTo: rootView.keyboardLayoutGuide.topAnchor, constant: 0),
|
|
78
|
+
heightAnchor.constraint(equalToConstant: 0),
|
|
79
|
+
])
|
|
71
80
|
}
|
|
72
|
-
|
|
73
|
-
NSLayoutConstraint.activate([
|
|
74
|
-
leadingAnchor.constraint(equalTo: rootView.leadingAnchor, constant: 0),
|
|
75
|
-
trailingAnchor.constraint(equalTo: rootView.trailingAnchor, constant: 0),
|
|
76
|
-
bottomAnchor.constraint(equalTo: rootView.keyboardLayoutGuide.topAnchor, constant: 0),
|
|
77
|
-
heightAnchor.constraint(equalToConstant: 0),
|
|
78
|
-
])
|
|
79
81
|
}
|
|
80
82
|
|
|
81
83
|
@objc private func keyboardWillAppear(_ notification: Notification) {
|
|
@@ -111,6 +113,11 @@ final class KeyboardTrackingView: UIView {
|
|
|
111
113
|
|
|
112
114
|
// for `keyboardLayoutGuide` case we can just read keyboard position directly - no interpolation needed
|
|
113
115
|
if #available(iOS 26.0, *) {
|
|
116
|
+
// when we are the top position KVO takes `inputAccessoryView` into consideration,
|
|
117
|
+
// so we handle it here
|
|
118
|
+
if keyboardPosition == keyboardHeight {
|
|
119
|
+
return keyboardPosition - KeyboardAreaExtender.shared.offset
|
|
120
|
+
}
|
|
114
121
|
return keyboardPosition
|
|
115
122
|
}
|
|
116
123
|
|
|
@@ -127,6 +134,6 @@ final class KeyboardTrackingView: UIView {
|
|
|
127
134
|
currentValue: keyboardPosition
|
|
128
135
|
)
|
|
129
136
|
|
|
130
|
-
return position
|
|
137
|
+
return position - KeyboardAreaExtender.shared.offset
|
|
131
138
|
}
|
|
132
139
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
//
|
|
2
|
+
// KeyboardMovementObserver+Animation.swift
|
|
3
|
+
// Pods
|
|
4
|
+
//
|
|
5
|
+
// Created by Kiryl Ziusko on 07/08/2025.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
extension KeyboardMovementObserver {
|
|
9
|
+
func initializeAnimation(fromValue: Double, toValue: Double) {
|
|
10
|
+
for key in ["position", "opacity"] {
|
|
11
|
+
if let keyboardAnimation = keyboardTrackingView.view?.layer.presentation()?.animation(forKey: key) {
|
|
12
|
+
if let springAnimation = keyboardAnimation as? CASpringAnimation {
|
|
13
|
+
animation = SpringAnimation(animation: springAnimation, fromValue: fromValue, toValue: toValue)
|
|
14
|
+
} else if let basicAnimation = keyboardAnimation as? CABasicAnimation {
|
|
15
|
+
animation = TimingAnimation(animation: basicAnimation, fromValue: fromValue, toValue: toValue)
|
|
16
|
+
}
|
|
17
|
+
return
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
//
|
|
2
|
+
// KeyboardMovementObserver+Interactive.swift
|
|
3
|
+
// Pods
|
|
4
|
+
//
|
|
5
|
+
// Created by Kiryl Ziusko on 07/08/2025.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
extension KeyboardMovementObserver {
|
|
9
|
+
func setupKVObserver() {
|
|
10
|
+
guard interactiveKeyboardObserver == nil, let view = keyboardTrackingView.view else { return }
|
|
11
|
+
|
|
12
|
+
interactiveKeyboardObserver = view.observe(\.center, options: .new) { [weak self] _, change in
|
|
13
|
+
guard let self = self, let changeValue = change.newValue else { return }
|
|
14
|
+
|
|
15
|
+
self.keyboardDidMoveInteractively(changeValue: changeValue)
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
func removeKVObserver() {
|
|
20
|
+
interactiveKeyboardObserver?.invalidate()
|
|
21
|
+
interactiveKeyboardObserver = nil
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
private func keyboardDidMoveInteractively(changeValue: CGPoint) {
|
|
25
|
+
if UIResponder.isKeyboardPreloading {
|
|
26
|
+
return
|
|
27
|
+
}
|
|
28
|
+
// if we are currently animating keyboard -> we need to ignore values from KVO
|
|
29
|
+
if !displayLink.isPaused {
|
|
30
|
+
return
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
let position = keyboardTrackingView.interactive(point: changeValue)
|
|
34
|
+
|
|
35
|
+
if position == KeyboardTrackingView.invalidPosition {
|
|
36
|
+
return
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if position == 0 {
|
|
40
|
+
// it will be triggered before `keyboardWillDisappear` and
|
|
41
|
+
// we don't need to trigger `onInteractive` handler for that
|
|
42
|
+
// since it will be handled in `keyboardWillDisappear` function
|
|
43
|
+
return
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
prevKeyboardPosition = position
|
|
47
|
+
|
|
48
|
+
onEvent(
|
|
49
|
+
"onKeyboardMoveInteractive",
|
|
50
|
+
position as NSNumber,
|
|
51
|
+
position / CGFloat(keyboardHeight) as NSNumber,
|
|
52
|
+
-1,
|
|
53
|
+
tag
|
|
54
|
+
)
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
//
|
|
2
|
+
// KeyboardMovementObserver+Lifecycle.swift
|
|
3
|
+
// Pods
|
|
4
|
+
//
|
|
5
|
+
// Created by Kiryl Ziusko on 07/08/2025.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
public extension KeyboardMovementObserver {
|
|
9
|
+
@objc func mount() {
|
|
10
|
+
if isMounted {
|
|
11
|
+
return
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
isMounted = true
|
|
15
|
+
|
|
16
|
+
NotificationCenter.default.addObserver(
|
|
17
|
+
self,
|
|
18
|
+
selector: #selector(keyboardWillDisappear),
|
|
19
|
+
name: UIResponder.keyboardWillHideNotification,
|
|
20
|
+
object: nil
|
|
21
|
+
)
|
|
22
|
+
NotificationCenter.default.addObserver(
|
|
23
|
+
self,
|
|
24
|
+
selector: #selector(keyboardWillAppear),
|
|
25
|
+
name: UIResponder.keyboardWillShowNotification,
|
|
26
|
+
object: nil
|
|
27
|
+
)
|
|
28
|
+
NotificationCenter.default.addObserver(
|
|
29
|
+
self,
|
|
30
|
+
selector: #selector(keyboardDidAppear),
|
|
31
|
+
name: UIResponder.keyboardDidShowNotification,
|
|
32
|
+
object: nil
|
|
33
|
+
)
|
|
34
|
+
NotificationCenter.default.addObserver(
|
|
35
|
+
self,
|
|
36
|
+
selector: #selector(keyboardDidDisappear),
|
|
37
|
+
name: UIResponder.keyboardDidHideNotification,
|
|
38
|
+
object: nil
|
|
39
|
+
)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
@objc func unmount() {
|
|
43
|
+
isMounted = false
|
|
44
|
+
// swiftlint:disable:next notification_center_detachment
|
|
45
|
+
NotificationCenter.default.removeObserver(self)
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
//
|
|
2
|
+
// KeyboardMovementObserver+Listeners.swift
|
|
3
|
+
// Pods
|
|
4
|
+
//
|
|
5
|
+
// Created by Kiryl Ziusko on 07/08/2025.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
extension KeyboardMovementObserver {
|
|
9
|
+
@objc func keyboardWillAppear(_ notification: Notification) {
|
|
10
|
+
guard !KeyboardEventsIgnorer.shared.shouldIgnore, !UIResponder.isKeyboardPreloading else { return }
|
|
11
|
+
|
|
12
|
+
let (duration, frame) = notification.keyboardMetaData()
|
|
13
|
+
if let keyboardFrame = frame {
|
|
14
|
+
tag = UIResponder.current.reactViewTag
|
|
15
|
+
let keyboardHeight = keyboardFrame.cgRectValue.size.height
|
|
16
|
+
self.keyboardHeight = keyboardHeight
|
|
17
|
+
self.duration = duration
|
|
18
|
+
didShowDeadline = Date.currentTimeStamp + Int64(duration)
|
|
19
|
+
|
|
20
|
+
onRequestAnimation()
|
|
21
|
+
onEvent("onKeyboardMoveStart", Float(self.keyboardHeight) as NSNumber, 1, duration as NSNumber, tag)
|
|
22
|
+
onNotify("KeyboardController::keyboardWillShow", buildEventParams(self.keyboardHeight, duration, tag))
|
|
23
|
+
|
|
24
|
+
setupKeyboardWatcher()
|
|
25
|
+
initializeAnimation(fromValue: prevKeyboardPosition, toValue: self.keyboardHeight)
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
@objc func keyboardWillDisappear(_ notification: Notification) {
|
|
30
|
+
guard !UIResponder.isKeyboardPreloading else { return }
|
|
31
|
+
let (duration, _) = notification.keyboardMetaData()
|
|
32
|
+
tag = UIResponder.current.reactViewTag
|
|
33
|
+
self.duration = duration
|
|
34
|
+
|
|
35
|
+
onRequestAnimation()
|
|
36
|
+
onEvent("onKeyboardMoveStart", 0, 0, duration as NSNumber, tag)
|
|
37
|
+
onNotify("KeyboardController::keyboardWillHide", buildEventParams(0, duration, tag))
|
|
38
|
+
|
|
39
|
+
setupKeyboardWatcher()
|
|
40
|
+
removeKVObserver()
|
|
41
|
+
initializeAnimation(fromValue: prevKeyboardPosition, toValue: 0)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
@objc func keyboardDidAppear(_ notification: Notification) {
|
|
45
|
+
guard !UIResponder.isKeyboardPreloading else { return }
|
|
46
|
+
|
|
47
|
+
let timestamp = Date.currentTimeStamp
|
|
48
|
+
let (duration, frame) = notification.keyboardMetaData()
|
|
49
|
+
if let keyboardFrame = frame {
|
|
50
|
+
let (position, _) = keyboardTrackingView.view.frameTransitionInWindow
|
|
51
|
+
let keyboardHeight = keyboardFrame.cgRectValue.size.height
|
|
52
|
+
tag = UIResponder.current.reactViewTag
|
|
53
|
+
self.keyboardHeight = keyboardHeight
|
|
54
|
+
|
|
55
|
+
guard !KeyboardEventsIgnorer.shared.shouldIgnore else {
|
|
56
|
+
KeyboardEventsIgnorer.shared.shouldIgnoreKeyboardEvents = false
|
|
57
|
+
return
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// if the event is caught in between it's highly likely that it could be a "resize" event
|
|
61
|
+
// so we just read actual keyboard frame value in this case
|
|
62
|
+
let height = timestamp >= didShowDeadline ? self.keyboardHeight : position - KeyboardAreaExtender.shared.offset
|
|
63
|
+
// always limit progress to the maximum possible value
|
|
64
|
+
let progress = min(height / self.keyboardHeight, 1.0)
|
|
65
|
+
|
|
66
|
+
onCancelAnimation()
|
|
67
|
+
onEvent("onKeyboardMoveEnd", height as NSNumber, progress as NSNumber, duration as NSNumber, tag)
|
|
68
|
+
onNotify("KeyboardController::keyboardDidShow", buildEventParams(height, duration, tag))
|
|
69
|
+
|
|
70
|
+
removeKeyboardWatcher()
|
|
71
|
+
setupKVObserver()
|
|
72
|
+
animation = nil
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
@objc func keyboardDidDisappear(_ notification: Notification) {
|
|
77
|
+
guard !UIResponder.isKeyboardPreloading else { return }
|
|
78
|
+
let (duration, _) = notification.keyboardMetaData()
|
|
79
|
+
tag = UIResponder.current.reactViewTag
|
|
80
|
+
|
|
81
|
+
onCancelAnimation()
|
|
82
|
+
onEvent("onKeyboardMoveEnd", 0 as NSNumber, 0, duration as NSNumber, tag)
|
|
83
|
+
onNotify("KeyboardController::keyboardDidHide", buildEventParams(0, duration, tag))
|
|
84
|
+
|
|
85
|
+
removeKeyboardWatcher()
|
|
86
|
+
animation = nil
|
|
87
|
+
}
|
|
88
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
//
|
|
2
|
+
// KeyboardMovementObserver+Watcher.swift
|
|
3
|
+
// Pods
|
|
4
|
+
//
|
|
5
|
+
// Created by Kiryl Ziusko on 07/08/2025.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
extension KeyboardMovementObserver {
|
|
9
|
+
@objc func setupKeyboardWatcher() {
|
|
10
|
+
// sometimes `will` events can be called multiple times.
|
|
11
|
+
// To avoid double re-creation of listener we are adding this condition
|
|
12
|
+
// (if active link is present, then no need to re-setup a listener)
|
|
13
|
+
if !displayLink.isPaused {
|
|
14
|
+
return
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
displayLink.isPaused = false
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
@objc func removeKeyboardWatcher() {
|
|
21
|
+
displayLink.isPaused = true
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
@objc func updateKeyboardFrame(link: CADisplayLink) {
|
|
25
|
+
if keyboardTrackingView.view == nil {
|
|
26
|
+
return
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
let (visibleKeyboardHeight, keyboardFrameY) = keyboardTrackingView.view.frameTransitionInWindow
|
|
30
|
+
var keyboardPosition = visibleKeyboardHeight - KeyboardAreaExtender.shared.offset
|
|
31
|
+
|
|
32
|
+
if keyboardPosition == prevKeyboardPosition || keyboardFrameY == 0 {
|
|
33
|
+
return
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if animation == nil {
|
|
37
|
+
initializeAnimation(fromValue: prevKeyboardPosition, toValue: keyboardHeight)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
prevKeyboardPosition = keyboardPosition
|
|
41
|
+
|
|
42
|
+
if let animation = animation {
|
|
43
|
+
let baseDuration = animation.timingAt(value: keyboardPosition)
|
|
44
|
+
|
|
45
|
+
#if targetEnvironment(simulator)
|
|
46
|
+
// on iOS simulator we can not use static interval
|
|
47
|
+
// (from my observation from frame to frame we may have different delays)
|
|
48
|
+
// so for now we use approximation - we add a difference as
|
|
49
|
+
// beginTime - keyboardEventTime (but only in 0..0.016 range)
|
|
50
|
+
// and it gives satisfactory results (better than static delays)
|
|
51
|
+
let duration = baseDuration + animation.diff
|
|
52
|
+
#else
|
|
53
|
+
// 2 frames because we read previous frame, but need to calculate the next frame
|
|
54
|
+
let duration = baseDuration + link.duration * 2
|
|
55
|
+
#endif
|
|
56
|
+
|
|
57
|
+
let position = CGFloat(animation.valueAt(time: duration))
|
|
58
|
+
// handles a case when final frame has final destination (i. e. 0 or 291)
|
|
59
|
+
// but CASpringAnimation can never get to this final destination
|
|
60
|
+
let race: (CGFloat, CGFloat) -> CGFloat = animation.isIncreasing ? max : min
|
|
61
|
+
keyboardPosition = race(position, keyboardPosition)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
onEvent(
|
|
65
|
+
"onKeyboardMove",
|
|
66
|
+
keyboardPosition as NSNumber,
|
|
67
|
+
keyboardPosition / CGFloat(keyboardHeight) as NSNumber,
|
|
68
|
+
duration as NSNumber,
|
|
69
|
+
tag
|
|
70
|
+
)
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
//
|
|
2
|
+
// KeyboardMovementObserver.swift
|
|
3
|
+
// KeyboardController
|
|
4
|
+
//
|
|
5
|
+
// Created by Kiryl Ziusko on 2.08.22.
|
|
6
|
+
// Copyright © 2022 Facebook. All rights reserved.
|
|
7
|
+
//
|
|
8
|
+
|
|
9
|
+
import Foundation
|
|
10
|
+
import UIKit
|
|
11
|
+
|
|
12
|
+
@objc(KeyboardMovementObserver)
|
|
13
|
+
public class KeyboardMovementObserver: NSObject {
|
|
14
|
+
// class members
|
|
15
|
+
var onEvent: (NSString, NSNumber, NSNumber, NSNumber, NSNumber) -> Void
|
|
16
|
+
var onNotify: (String, Any) -> Void
|
|
17
|
+
// animation
|
|
18
|
+
var onRequestAnimation: () -> Void
|
|
19
|
+
var onCancelAnimation: () -> Void
|
|
20
|
+
// progress tracker
|
|
21
|
+
var keyboardTrackingView = KeyboardTrackingView()
|
|
22
|
+
var animation: KeyboardAnimation?
|
|
23
|
+
|
|
24
|
+
var prevKeyboardPosition = 0.0
|
|
25
|
+
var displayLink: CADisplayLink!
|
|
26
|
+
var interactiveKeyboardObserver: NSKeyValueObservation?
|
|
27
|
+
var isMounted = false
|
|
28
|
+
// state variables
|
|
29
|
+
private var _keyboardHeight: CGFloat = 0.0
|
|
30
|
+
var keyboardHeight: CGFloat {
|
|
31
|
+
get { _keyboardHeight - KeyboardAreaExtender.shared.offset }
|
|
32
|
+
set { _keyboardHeight = newValue }
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
var duration = 0
|
|
36
|
+
var tag: NSNumber = -1
|
|
37
|
+
var didShowDeadline: Int64 = 0
|
|
38
|
+
|
|
39
|
+
@objc public init(
|
|
40
|
+
handler: @escaping (NSString, NSNumber, NSNumber, NSNumber, NSNumber) -> Void,
|
|
41
|
+
onNotify: @escaping (String, Any) -> Void,
|
|
42
|
+
onRequestAnimation: @escaping () -> Void,
|
|
43
|
+
onCancelAnimation: @escaping () -> Void
|
|
44
|
+
) {
|
|
45
|
+
onEvent = handler
|
|
46
|
+
self.onNotify = onNotify
|
|
47
|
+
self.onRequestAnimation = onRequestAnimation
|
|
48
|
+
self.onCancelAnimation = onCancelAnimation
|
|
49
|
+
|
|
50
|
+
super.init()
|
|
51
|
+
|
|
52
|
+
displayLink = CADisplayLink(target: self, selector: #selector(updateKeyboardFrame))
|
|
53
|
+
displayLink.preferredFramesPerSecond = 120 // will fallback to 60 fps for devices without Pro Motion display
|
|
54
|
+
displayLink.add(to: .main, forMode: .common)
|
|
55
|
+
displayLink.isPaused = true
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
deinit {
|
|
59
|
+
displayLink.invalidate()
|
|
60
|
+
displayLink = nil
|
|
61
|
+
NotificationCenter.default.removeObserver(self)
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -10,11 +10,13 @@ import UIKit
|
|
|
10
10
|
@objc
|
|
11
11
|
public class KeyboardExtenderContainerView: NSObject {
|
|
12
12
|
@objc public static func create(frame: CGRect, contentView: UIView) -> UIView {
|
|
13
|
-
if
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
13
|
+
#if canImport(UIKit.UIGlassEffect)
|
|
14
|
+
if #available(iOS 26.0, *) {
|
|
15
|
+
return ModernContainerView(frame: frame, contentView: contentView)
|
|
16
|
+
}
|
|
17
|
+
#endif
|
|
18
|
+
|
|
19
|
+
return LegacyContainerView(frame: frame, contentView: contentView)
|
|
18
20
|
}
|
|
19
21
|
}
|
|
20
22
|
|
|
@@ -86,21 +88,23 @@ private class ModernContainerView: BaseContainerView {
|
|
|
86
88
|
}
|
|
87
89
|
|
|
88
90
|
private func setupVisualEffect() {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
visualEffectView
|
|
102
|
-
|
|
103
|
-
|
|
91
|
+
#if canImport(UIKit.UIGlassEffect)
|
|
92
|
+
let isDark = FocusedInputHolder.shared.get()?.keyboardAppearanceValue == "dark"
|
|
93
|
+
let glassEffect = UIGlassEffect()
|
|
94
|
+
let color =
|
|
95
|
+
isDark ? UIColor.black.withAlphaComponent(0.3) : UIColor.gray.withAlphaComponent(0.3)
|
|
96
|
+
glassEffect.tintColor = color
|
|
97
|
+
glassEffect.isInteractive = true
|
|
98
|
+
|
|
99
|
+
visualEffectView = UIVisualEffectView(effect: glassEffect)
|
|
100
|
+
visualEffectView?.overrideUserInterfaceStyle = isDark ? .dark : .light
|
|
101
|
+
visualEffectView?.cornerConfiguration = .capsule()
|
|
102
|
+
|
|
103
|
+
if let visualEffectView = visualEffectView {
|
|
104
|
+
visualEffectView.contentView.addSubview(contentView)
|
|
105
|
+
addSubview(visualEffectView)
|
|
106
|
+
}
|
|
107
|
+
#endif
|
|
104
108
|
}
|
|
105
109
|
|
|
106
110
|
override func updateContentFrame(desiredHeight: CGFloat) {
|
|
@@ -76,11 +76,13 @@ const KeyboardAvoidingView = /*#__PURE__*/(0, _react.forwardRef)(({
|
|
|
76
76
|
onLayoutProps === null || onLayoutProps === void 0 || onLayoutProps(e);
|
|
77
77
|
}, [onLayoutProps]);
|
|
78
78
|
const animatedStyle = (0, _reactNativeReanimated.useAnimatedStyle)(() => {
|
|
79
|
+
if (!enabled) {
|
|
80
|
+
return {};
|
|
81
|
+
}
|
|
79
82
|
const bottom = interpolateToRelativeKeyboardHeight(keyboard.progress.value);
|
|
80
83
|
const translateY = interpolateToRelativeKeyboardHeight(translate.value);
|
|
81
84
|
const paddingBottom = interpolateToRelativeKeyboardHeight(padding.value);
|
|
82
|
-
const
|
|
83
|
-
const height = frame.value.height - bottomHeight;
|
|
85
|
+
const height = frame.value.height - bottom;
|
|
84
86
|
switch (behavior) {
|
|
85
87
|
case "height":
|
|
86
88
|
if (!keyboard.isClosed.value && height > 0) {
|
|
@@ -92,11 +94,11 @@ const KeyboardAvoidingView = /*#__PURE__*/(0, _react.forwardRef)(({
|
|
|
92
94
|
return {};
|
|
93
95
|
case "position":
|
|
94
96
|
return {
|
|
95
|
-
bottom
|
|
97
|
+
bottom
|
|
96
98
|
};
|
|
97
99
|
case "padding":
|
|
98
100
|
return {
|
|
99
|
-
paddingBottom:
|
|
101
|
+
paddingBottom: bottom
|
|
100
102
|
};
|
|
101
103
|
case "translate-with-padding":
|
|
102
104
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_react","_interopRequireWildcard","require","_reactNative","_reactNativeReanimated","_hooks","_hooks2","_getRequireWildcardCache","e","WeakMap","r","t","__esModule","default","has","get","n","__proto__","a","Object","defineProperty","getOwnPropertyDescriptor","u","hasOwnProperty","call","i","set","_extends","assign","bind","arguments","length","apply","defaultLayout","x","y","width","height","KeyboardAvoidingView","forwardRef","behavior","children","contentContainerStyle","enabled","keyboardVerticalOffset","style","onLayout","onLayoutProps","props","ref","initialFrame","useSharedValue","frame","useDerivedValue","value","translate","padding","useTranslateAnimation","keyboard","useKeyboardAnimation","screenHeight","useWindowDimensions","relativeKeyboardHeight","useCallback","keyboardY","heightWhenOpened","Math","max","interpolateToRelativeKeyboardHeight","interpolate","onLayoutWorklet","layout","isClosed","runOnUI","nativeEvent","animatedStyle","useAnimatedStyle","bottom","progress","translateY","paddingBottom","bottomHeight","flex","paddingTop","transform","isPositionBehavior","containerStyle","combinedStyles","useMemo","createElement","View","_default","exports"],"sources":["index.tsx"],"sourcesContent":["import React, { forwardRef, useCallback, useMemo } from \"react\";\nimport { View } from \"react-native\";\nimport Reanimated, {\n interpolate,\n runOnUI,\n useAnimatedStyle,\n useDerivedValue,\n useSharedValue,\n} from \"react-native-reanimated\";\n\nimport { useWindowDimensions } from \"../../hooks\";\n\nimport { useKeyboardAnimation, useTranslateAnimation } from \"./hooks\";\n\nimport type { LayoutRectangle, ViewProps } from \"react-native\";\n\nexport type KeyboardAvoidingViewBaseProps = {\n /**\n * Controls whether this `KeyboardAvoidingView` instance should take effect.\n * This is useful when more than one is on the screen. Defaults to true.\n */\n enabled?: boolean;\n\n /**\n * Distance between the top of the user screen and the React Native view. This\n * may be non-zero in some cases. Defaults to 0.\n */\n keyboardVerticalOffset?: number;\n} & ViewProps;\n\nexport type KeyboardAvoidingViewProps = KeyboardAvoidingViewBaseProps &\n (\n | {\n /**\n * Specify how to react to the presence of the keyboard.\n */\n behavior?: \"position\";\n\n /**\n * Style of the content container when `behavior` is 'position'.\n */\n contentContainerStyle?: ViewProps[\"style\"];\n }\n | {\n /**\n * Specify how to react to the presence of the keyboard.\n */\n behavior?: \"height\" | \"padding\" | \"translate-with-padding\";\n\n /**\n * `contentContainerStyle` is not allowed for these behaviors.\n */\n contentContainerStyle?: never;\n }\n );\n\nconst defaultLayout: LayoutRectangle = {\n x: 0,\n y: 0,\n width: 0,\n height: 0,\n};\n\n/**\n * A View component that automatically adjusts its height, position, or bottom padding\n * when the keyboard appears to ensure that the content remains visible.\n *\n * @returns A View component that adjusts to keyboard visibility.\n * @see {@link https://kirillzyusko.github.io/react-native-keyboard-controller/docs/api/components/keyboard-avoiding-view|Documentation} page for more details.\n * @example\n * ```tsx\n * <KeyboardAvoidingView behavior=\"padding\">\n * <TextInput />\n * </KeyboardAvoidingView>\n * ```\n */\nconst KeyboardAvoidingView = forwardRef<\n View,\n React.PropsWithChildren<KeyboardAvoidingViewProps>\n>(\n (\n {\n behavior,\n children,\n contentContainerStyle,\n enabled = true,\n keyboardVerticalOffset = 0,\n style,\n onLayout: onLayoutProps,\n ...props\n },\n ref,\n ) => {\n const initialFrame = useSharedValue<LayoutRectangle | null>(null);\n const frame = useDerivedValue(() => initialFrame.value || defaultLayout);\n\n const { translate, padding } = useTranslateAnimation();\n const keyboard = useKeyboardAnimation();\n const { height: screenHeight } = useWindowDimensions();\n\n const relativeKeyboardHeight = useCallback(() => {\n \"worklet\";\n\n const keyboardY =\n screenHeight - keyboard.heightWhenOpened.value - keyboardVerticalOffset;\n\n return Math.max(frame.value.y + frame.value.height - keyboardY, 0);\n }, [screenHeight, keyboardVerticalOffset]);\n const interpolateToRelativeKeyboardHeight = useCallback(\n (value: number) => {\n \"worklet\";\n\n return interpolate(value, [0, 1], [0, relativeKeyboardHeight()]);\n },\n [relativeKeyboardHeight],\n );\n\n const onLayoutWorklet = useCallback(\n (layout: LayoutRectangle) => {\n \"worklet\";\n\n if (\n keyboard.isClosed.value ||\n initialFrame.value === null ||\n behavior !== \"height\"\n ) {\n // eslint-disable-next-line react-compiler/react-compiler\n initialFrame.value = layout;\n }\n },\n [behavior],\n );\n const onLayout = useCallback<NonNullable<ViewProps[\"onLayout\"]>>(\n (e) => {\n runOnUI(onLayoutWorklet)(e.nativeEvent.layout);\n onLayoutProps?.(e);\n },\n [onLayoutProps],\n );\n\n const animatedStyle = useAnimatedStyle(() => {\n const bottom = interpolateToRelativeKeyboardHeight(\n keyboard.progress.value,\n );\n const translateY = interpolateToRelativeKeyboardHeight(translate.value);\n const paddingBottom = interpolateToRelativeKeyboardHeight(padding.value);\n const bottomHeight = enabled ? bottom : 0;\n const height = frame.value.height - bottomHeight;\n\n switch (behavior) {\n case \"height\":\n if (!keyboard.isClosed.value && height > 0) {\n return {\n height,\n flex: 0,\n };\n }\n\n return {};\n\n case \"position\":\n return { bottom: bottomHeight };\n\n case \"padding\":\n return { paddingBottom: bottomHeight };\n\n case \"translate-with-padding\":\n return {\n paddingTop: paddingBottom,\n transform: [{ translateY: -translateY }],\n };\n\n default:\n return {};\n }\n }, [behavior, enabled, interpolateToRelativeKeyboardHeight]);\n const isPositionBehavior = behavior === \"position\";\n const containerStyle = isPositionBehavior ? contentContainerStyle : style;\n const combinedStyles = useMemo(\n () => [containerStyle, animatedStyle],\n [containerStyle, animatedStyle],\n );\n\n if (isPositionBehavior) {\n return (\n <View ref={ref} style={style} onLayout={onLayout} {...props}>\n <Reanimated.View style={combinedStyles}>{children}</Reanimated.View>\n </View>\n );\n }\n\n return (\n <Reanimated.View\n ref={ref}\n style={combinedStyles}\n onLayout={onLayout}\n {...props}\n >\n {children}\n </Reanimated.View>\n );\n },\n);\n\nexport default KeyboardAvoidingView;\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":["_react","_interopRequireWildcard","require","_reactNative","_reactNativeReanimated","_hooks","_hooks2","_getRequireWildcardCache","e","WeakMap","r","t","__esModule","default","has","get","n","__proto__","a","Object","defineProperty","getOwnPropertyDescriptor","u","hasOwnProperty","call","i","set","_extends","assign","bind","arguments","length","apply","defaultLayout","x","y","width","height","KeyboardAvoidingView","forwardRef","behavior","children","contentContainerStyle","enabled","keyboardVerticalOffset","style","onLayout","onLayoutProps","props","ref","initialFrame","useSharedValue","frame","useDerivedValue","value","translate","padding","useTranslateAnimation","keyboard","useKeyboardAnimation","screenHeight","useWindowDimensions","relativeKeyboardHeight","useCallback","keyboardY","heightWhenOpened","Math","max","interpolateToRelativeKeyboardHeight","interpolate","onLayoutWorklet","layout","isClosed","runOnUI","nativeEvent","animatedStyle","useAnimatedStyle","bottom","progress","translateY","paddingBottom","flex","paddingTop","transform","isPositionBehavior","containerStyle","combinedStyles","useMemo","createElement","View","_default","exports"],"sources":["index.tsx"],"sourcesContent":["import React, { forwardRef, useCallback, useMemo } from \"react\";\nimport { View } from \"react-native\";\nimport Reanimated, {\n interpolate,\n runOnUI,\n useAnimatedStyle,\n useDerivedValue,\n useSharedValue,\n} from \"react-native-reanimated\";\n\nimport { useWindowDimensions } from \"../../hooks\";\n\nimport { useKeyboardAnimation, useTranslateAnimation } from \"./hooks\";\n\nimport type { LayoutRectangle, ViewProps } from \"react-native\";\n\nexport type KeyboardAvoidingViewBaseProps = {\n /**\n * Controls whether this `KeyboardAvoidingView` instance should take effect.\n * This is useful when more than one is on the screen. Defaults to true.\n */\n enabled?: boolean;\n\n /**\n * Distance between the top of the user screen and the React Native view. This\n * may be non-zero in some cases. Defaults to 0.\n */\n keyboardVerticalOffset?: number;\n} & ViewProps;\n\nexport type KeyboardAvoidingViewProps = KeyboardAvoidingViewBaseProps &\n (\n | {\n /**\n * Specify how to react to the presence of the keyboard.\n */\n behavior?: \"position\";\n\n /**\n * Style of the content container when `behavior` is 'position'.\n */\n contentContainerStyle?: ViewProps[\"style\"];\n }\n | {\n /**\n * Specify how to react to the presence of the keyboard.\n */\n behavior?: \"height\" | \"padding\" | \"translate-with-padding\";\n\n /**\n * `contentContainerStyle` is not allowed for these behaviors.\n */\n contentContainerStyle?: never;\n }\n );\n\nconst defaultLayout: LayoutRectangle = {\n x: 0,\n y: 0,\n width: 0,\n height: 0,\n};\n\n/**\n * A View component that automatically adjusts its height, position, or bottom padding\n * when the keyboard appears to ensure that the content remains visible.\n *\n * @returns A View component that adjusts to keyboard visibility.\n * @see {@link https://kirillzyusko.github.io/react-native-keyboard-controller/docs/api/components/keyboard-avoiding-view|Documentation} page for more details.\n * @example\n * ```tsx\n * <KeyboardAvoidingView behavior=\"padding\">\n * <TextInput />\n * </KeyboardAvoidingView>\n * ```\n */\nconst KeyboardAvoidingView = forwardRef<\n View,\n React.PropsWithChildren<KeyboardAvoidingViewProps>\n>(\n (\n {\n behavior,\n children,\n contentContainerStyle,\n enabled = true,\n keyboardVerticalOffset = 0,\n style,\n onLayout: onLayoutProps,\n ...props\n },\n ref,\n ) => {\n const initialFrame = useSharedValue<LayoutRectangle | null>(null);\n const frame = useDerivedValue(() => initialFrame.value || defaultLayout);\n\n const { translate, padding } = useTranslateAnimation();\n const keyboard = useKeyboardAnimation();\n const { height: screenHeight } = useWindowDimensions();\n\n const relativeKeyboardHeight = useCallback(() => {\n \"worklet\";\n\n const keyboardY =\n screenHeight - keyboard.heightWhenOpened.value - keyboardVerticalOffset;\n\n return Math.max(frame.value.y + frame.value.height - keyboardY, 0);\n }, [screenHeight, keyboardVerticalOffset]);\n const interpolateToRelativeKeyboardHeight = useCallback(\n (value: number) => {\n \"worklet\";\n\n return interpolate(value, [0, 1], [0, relativeKeyboardHeight()]);\n },\n [relativeKeyboardHeight],\n );\n\n const onLayoutWorklet = useCallback(\n (layout: LayoutRectangle) => {\n \"worklet\";\n\n if (\n keyboard.isClosed.value ||\n initialFrame.value === null ||\n behavior !== \"height\"\n ) {\n // eslint-disable-next-line react-compiler/react-compiler\n initialFrame.value = layout;\n }\n },\n [behavior],\n );\n const onLayout = useCallback<NonNullable<ViewProps[\"onLayout\"]>>(\n (e) => {\n runOnUI(onLayoutWorklet)(e.nativeEvent.layout);\n onLayoutProps?.(e);\n },\n [onLayoutProps],\n );\n\n const animatedStyle = useAnimatedStyle(() => {\n if (!enabled) {\n return {};\n }\n\n const bottom = interpolateToRelativeKeyboardHeight(\n keyboard.progress.value,\n );\n const translateY = interpolateToRelativeKeyboardHeight(translate.value);\n const paddingBottom = interpolateToRelativeKeyboardHeight(padding.value);\n const height = frame.value.height - bottom;\n\n switch (behavior) {\n case \"height\":\n if (!keyboard.isClosed.value && height > 0) {\n return {\n height,\n flex: 0,\n };\n }\n\n return {};\n\n case \"position\":\n return { bottom };\n\n case \"padding\":\n return { paddingBottom: bottom };\n\n case \"translate-with-padding\":\n return {\n paddingTop: paddingBottom,\n transform: [{ translateY: -translateY }],\n };\n\n default:\n return {};\n }\n }, [behavior, enabled, interpolateToRelativeKeyboardHeight]);\n const isPositionBehavior = behavior === \"position\";\n const containerStyle = isPositionBehavior ? contentContainerStyle : style;\n const combinedStyles = useMemo(\n () => [containerStyle, animatedStyle],\n [containerStyle, animatedStyle],\n );\n\n if (isPositionBehavior) {\n return (\n <View ref={ref} style={style} onLayout={onLayout} {...props}>\n <Reanimated.View style={combinedStyles}>{children}</Reanimated.View>\n </View>\n );\n }\n\n return (\n <Reanimated.View\n ref={ref}\n style={combinedStyles}\n onLayout={onLayout}\n {...props}\n >\n {children}\n </Reanimated.View>\n );\n },\n);\n\nexport default KeyboardAvoidingView;\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -68,11 +68,13 @@ const KeyboardAvoidingView = /*#__PURE__*/forwardRef(({
|
|
|
68
68
|
onLayoutProps === null || onLayoutProps === void 0 || onLayoutProps(e);
|
|
69
69
|
}, [onLayoutProps]);
|
|
70
70
|
const animatedStyle = useAnimatedStyle(() => {
|
|
71
|
+
if (!enabled) {
|
|
72
|
+
return {};
|
|
73
|
+
}
|
|
71
74
|
const bottom = interpolateToRelativeKeyboardHeight(keyboard.progress.value);
|
|
72
75
|
const translateY = interpolateToRelativeKeyboardHeight(translate.value);
|
|
73
76
|
const paddingBottom = interpolateToRelativeKeyboardHeight(padding.value);
|
|
74
|
-
const
|
|
75
|
-
const height = frame.value.height - bottomHeight;
|
|
77
|
+
const height = frame.value.height - bottom;
|
|
76
78
|
switch (behavior) {
|
|
77
79
|
case "height":
|
|
78
80
|
if (!keyboard.isClosed.value && height > 0) {
|
|
@@ -84,11 +86,11 @@ const KeyboardAvoidingView = /*#__PURE__*/forwardRef(({
|
|
|
84
86
|
return {};
|
|
85
87
|
case "position":
|
|
86
88
|
return {
|
|
87
|
-
bottom
|
|
89
|
+
bottom
|
|
88
90
|
};
|
|
89
91
|
case "padding":
|
|
90
92
|
return {
|
|
91
|
-
paddingBottom:
|
|
93
|
+
paddingBottom: bottom
|
|
92
94
|
};
|
|
93
95
|
case "translate-with-padding":
|
|
94
96
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["React","forwardRef","useCallback","useMemo","View","Reanimated","interpolate","runOnUI","useAnimatedStyle","useDerivedValue","useSharedValue","useWindowDimensions","useKeyboardAnimation","useTranslateAnimation","defaultLayout","x","y","width","height","KeyboardAvoidingView","behavior","children","contentContainerStyle","enabled","keyboardVerticalOffset","style","onLayout","onLayoutProps","props","ref","initialFrame","frame","value","translate","padding","keyboard","screenHeight","relativeKeyboardHeight","keyboardY","heightWhenOpened","Math","max","interpolateToRelativeKeyboardHeight","onLayoutWorklet","layout","isClosed","e","nativeEvent","animatedStyle","bottom","progress","translateY","paddingBottom","bottomHeight","flex","paddingTop","transform","isPositionBehavior","containerStyle","combinedStyles","createElement","_extends"],"sources":["index.tsx"],"sourcesContent":["import React, { forwardRef, useCallback, useMemo } from \"react\";\nimport { View } from \"react-native\";\nimport Reanimated, {\n interpolate,\n runOnUI,\n useAnimatedStyle,\n useDerivedValue,\n useSharedValue,\n} from \"react-native-reanimated\";\n\nimport { useWindowDimensions } from \"../../hooks\";\n\nimport { useKeyboardAnimation, useTranslateAnimation } from \"./hooks\";\n\nimport type { LayoutRectangle, ViewProps } from \"react-native\";\n\nexport type KeyboardAvoidingViewBaseProps = {\n /**\n * Controls whether this `KeyboardAvoidingView` instance should take effect.\n * This is useful when more than one is on the screen. Defaults to true.\n */\n enabled?: boolean;\n\n /**\n * Distance between the top of the user screen and the React Native view. This\n * may be non-zero in some cases. Defaults to 0.\n */\n keyboardVerticalOffset?: number;\n} & ViewProps;\n\nexport type KeyboardAvoidingViewProps = KeyboardAvoidingViewBaseProps &\n (\n | {\n /**\n * Specify how to react to the presence of the keyboard.\n */\n behavior?: \"position\";\n\n /**\n * Style of the content container when `behavior` is 'position'.\n */\n contentContainerStyle?: ViewProps[\"style\"];\n }\n | {\n /**\n * Specify how to react to the presence of the keyboard.\n */\n behavior?: \"height\" | \"padding\" | \"translate-with-padding\";\n\n /**\n * `contentContainerStyle` is not allowed for these behaviors.\n */\n contentContainerStyle?: never;\n }\n );\n\nconst defaultLayout: LayoutRectangle = {\n x: 0,\n y: 0,\n width: 0,\n height: 0,\n};\n\n/**\n * A View component that automatically adjusts its height, position, or bottom padding\n * when the keyboard appears to ensure that the content remains visible.\n *\n * @returns A View component that adjusts to keyboard visibility.\n * @see {@link https://kirillzyusko.github.io/react-native-keyboard-controller/docs/api/components/keyboard-avoiding-view|Documentation} page for more details.\n * @example\n * ```tsx\n * <KeyboardAvoidingView behavior=\"padding\">\n * <TextInput />\n * </KeyboardAvoidingView>\n * ```\n */\nconst KeyboardAvoidingView = forwardRef<\n View,\n React.PropsWithChildren<KeyboardAvoidingViewProps>\n>(\n (\n {\n behavior,\n children,\n contentContainerStyle,\n enabled = true,\n keyboardVerticalOffset = 0,\n style,\n onLayout: onLayoutProps,\n ...props\n },\n ref,\n ) => {\n const initialFrame = useSharedValue<LayoutRectangle | null>(null);\n const frame = useDerivedValue(() => initialFrame.value || defaultLayout);\n\n const { translate, padding } = useTranslateAnimation();\n const keyboard = useKeyboardAnimation();\n const { height: screenHeight } = useWindowDimensions();\n\n const relativeKeyboardHeight = useCallback(() => {\n \"worklet\";\n\n const keyboardY =\n screenHeight - keyboard.heightWhenOpened.value - keyboardVerticalOffset;\n\n return Math.max(frame.value.y + frame.value.height - keyboardY, 0);\n }, [screenHeight, keyboardVerticalOffset]);\n const interpolateToRelativeKeyboardHeight = useCallback(\n (value: number) => {\n \"worklet\";\n\n return interpolate(value, [0, 1], [0, relativeKeyboardHeight()]);\n },\n [relativeKeyboardHeight],\n );\n\n const onLayoutWorklet = useCallback(\n (layout: LayoutRectangle) => {\n \"worklet\";\n\n if (\n keyboard.isClosed.value ||\n initialFrame.value === null ||\n behavior !== \"height\"\n ) {\n // eslint-disable-next-line react-compiler/react-compiler\n initialFrame.value = layout;\n }\n },\n [behavior],\n );\n const onLayout = useCallback<NonNullable<ViewProps[\"onLayout\"]>>(\n (e) => {\n runOnUI(onLayoutWorklet)(e.nativeEvent.layout);\n onLayoutProps?.(e);\n },\n [onLayoutProps],\n );\n\n const animatedStyle = useAnimatedStyle(() => {\n const bottom = interpolateToRelativeKeyboardHeight(\n keyboard.progress.value,\n );\n const translateY = interpolateToRelativeKeyboardHeight(translate.value);\n const paddingBottom = interpolateToRelativeKeyboardHeight(padding.value);\n const bottomHeight = enabled ? bottom : 0;\n const height = frame.value.height - bottomHeight;\n\n switch (behavior) {\n case \"height\":\n if (!keyboard.isClosed.value && height > 0) {\n return {\n height,\n flex: 0,\n };\n }\n\n return {};\n\n case \"position\":\n return { bottom: bottomHeight };\n\n case \"padding\":\n return { paddingBottom: bottomHeight };\n\n case \"translate-with-padding\":\n return {\n paddingTop: paddingBottom,\n transform: [{ translateY: -translateY }],\n };\n\n default:\n return {};\n }\n }, [behavior, enabled, interpolateToRelativeKeyboardHeight]);\n const isPositionBehavior = behavior === \"position\";\n const containerStyle = isPositionBehavior ? contentContainerStyle : style;\n const combinedStyles = useMemo(\n () => [containerStyle, animatedStyle],\n [containerStyle, animatedStyle],\n );\n\n if (isPositionBehavior) {\n return (\n <View ref={ref} style={style} onLayout={onLayout} {...props}>\n <Reanimated.View style={combinedStyles}>{children}</Reanimated.View>\n </View>\n );\n }\n\n return (\n <Reanimated.View\n ref={ref}\n style={combinedStyles}\n onLayout={onLayout}\n {...props}\n >\n {children}\n </Reanimated.View>\n );\n },\n);\n\nexport default KeyboardAvoidingView;\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":["React","forwardRef","useCallback","useMemo","View","Reanimated","interpolate","runOnUI","useAnimatedStyle","useDerivedValue","useSharedValue","useWindowDimensions","useKeyboardAnimation","useTranslateAnimation","defaultLayout","x","y","width","height","KeyboardAvoidingView","behavior","children","contentContainerStyle","enabled","keyboardVerticalOffset","style","onLayout","onLayoutProps","props","ref","initialFrame","frame","value","translate","padding","keyboard","screenHeight","relativeKeyboardHeight","keyboardY","heightWhenOpened","Math","max","interpolateToRelativeKeyboardHeight","onLayoutWorklet","layout","isClosed","e","nativeEvent","animatedStyle","bottom","progress","translateY","paddingBottom","flex","paddingTop","transform","isPositionBehavior","containerStyle","combinedStyles","createElement","_extends"],"sources":["index.tsx"],"sourcesContent":["import React, { forwardRef, useCallback, useMemo } from \"react\";\nimport { View } from \"react-native\";\nimport Reanimated, {\n interpolate,\n runOnUI,\n useAnimatedStyle,\n useDerivedValue,\n useSharedValue,\n} from \"react-native-reanimated\";\n\nimport { useWindowDimensions } from \"../../hooks\";\n\nimport { useKeyboardAnimation, useTranslateAnimation } from \"./hooks\";\n\nimport type { LayoutRectangle, ViewProps } from \"react-native\";\n\nexport type KeyboardAvoidingViewBaseProps = {\n /**\n * Controls whether this `KeyboardAvoidingView` instance should take effect.\n * This is useful when more than one is on the screen. Defaults to true.\n */\n enabled?: boolean;\n\n /**\n * Distance between the top of the user screen and the React Native view. This\n * may be non-zero in some cases. Defaults to 0.\n */\n keyboardVerticalOffset?: number;\n} & ViewProps;\n\nexport type KeyboardAvoidingViewProps = KeyboardAvoidingViewBaseProps &\n (\n | {\n /**\n * Specify how to react to the presence of the keyboard.\n */\n behavior?: \"position\";\n\n /**\n * Style of the content container when `behavior` is 'position'.\n */\n contentContainerStyle?: ViewProps[\"style\"];\n }\n | {\n /**\n * Specify how to react to the presence of the keyboard.\n */\n behavior?: \"height\" | \"padding\" | \"translate-with-padding\";\n\n /**\n * `contentContainerStyle` is not allowed for these behaviors.\n */\n contentContainerStyle?: never;\n }\n );\n\nconst defaultLayout: LayoutRectangle = {\n x: 0,\n y: 0,\n width: 0,\n height: 0,\n};\n\n/**\n * A View component that automatically adjusts its height, position, or bottom padding\n * when the keyboard appears to ensure that the content remains visible.\n *\n * @returns A View component that adjusts to keyboard visibility.\n * @see {@link https://kirillzyusko.github.io/react-native-keyboard-controller/docs/api/components/keyboard-avoiding-view|Documentation} page for more details.\n * @example\n * ```tsx\n * <KeyboardAvoidingView behavior=\"padding\">\n * <TextInput />\n * </KeyboardAvoidingView>\n * ```\n */\nconst KeyboardAvoidingView = forwardRef<\n View,\n React.PropsWithChildren<KeyboardAvoidingViewProps>\n>(\n (\n {\n behavior,\n children,\n contentContainerStyle,\n enabled = true,\n keyboardVerticalOffset = 0,\n style,\n onLayout: onLayoutProps,\n ...props\n },\n ref,\n ) => {\n const initialFrame = useSharedValue<LayoutRectangle | null>(null);\n const frame = useDerivedValue(() => initialFrame.value || defaultLayout);\n\n const { translate, padding } = useTranslateAnimation();\n const keyboard = useKeyboardAnimation();\n const { height: screenHeight } = useWindowDimensions();\n\n const relativeKeyboardHeight = useCallback(() => {\n \"worklet\";\n\n const keyboardY =\n screenHeight - keyboard.heightWhenOpened.value - keyboardVerticalOffset;\n\n return Math.max(frame.value.y + frame.value.height - keyboardY, 0);\n }, [screenHeight, keyboardVerticalOffset]);\n const interpolateToRelativeKeyboardHeight = useCallback(\n (value: number) => {\n \"worklet\";\n\n return interpolate(value, [0, 1], [0, relativeKeyboardHeight()]);\n },\n [relativeKeyboardHeight],\n );\n\n const onLayoutWorklet = useCallback(\n (layout: LayoutRectangle) => {\n \"worklet\";\n\n if (\n keyboard.isClosed.value ||\n initialFrame.value === null ||\n behavior !== \"height\"\n ) {\n // eslint-disable-next-line react-compiler/react-compiler\n initialFrame.value = layout;\n }\n },\n [behavior],\n );\n const onLayout = useCallback<NonNullable<ViewProps[\"onLayout\"]>>(\n (e) => {\n runOnUI(onLayoutWorklet)(e.nativeEvent.layout);\n onLayoutProps?.(e);\n },\n [onLayoutProps],\n );\n\n const animatedStyle = useAnimatedStyle(() => {\n if (!enabled) {\n return {};\n }\n\n const bottom = interpolateToRelativeKeyboardHeight(\n keyboard.progress.value,\n );\n const translateY = interpolateToRelativeKeyboardHeight(translate.value);\n const paddingBottom = interpolateToRelativeKeyboardHeight(padding.value);\n const height = frame.value.height - bottom;\n\n switch (behavior) {\n case \"height\":\n if (!keyboard.isClosed.value && height > 0) {\n return {\n height,\n flex: 0,\n };\n }\n\n return {};\n\n case \"position\":\n return { bottom };\n\n case \"padding\":\n return { paddingBottom: bottom };\n\n case \"translate-with-padding\":\n return {\n paddingTop: paddingBottom,\n transform: [{ translateY: -translateY }],\n };\n\n default:\n return {};\n }\n }, [behavior, enabled, interpolateToRelativeKeyboardHeight]);\n const isPositionBehavior = behavior === \"position\";\n const containerStyle = isPositionBehavior ? contentContainerStyle : style;\n const combinedStyles = useMemo(\n () => [containerStyle, animatedStyle],\n [containerStyle, animatedStyle],\n );\n\n if (isPositionBehavior) {\n return (\n <View ref={ref} style={style} onLayout={onLayout} {...props}>\n <Reanimated.View style={combinedStyles}>{children}</Reanimated.View>\n </View>\n );\n }\n\n return (\n <Reanimated.View\n ref={ref}\n style={combinedStyles}\n onLayout={onLayout}\n {...props}\n >\n {children}\n </Reanimated.View>\n );\n },\n);\n\nexport default KeyboardAvoidingView;\n"],"mappings":"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","ignoreList":[]}
|
package/package.json
CHANGED
|
@@ -139,13 +139,16 @@ const KeyboardAvoidingView = forwardRef<
|
|
|
139
139
|
);
|
|
140
140
|
|
|
141
141
|
const animatedStyle = useAnimatedStyle(() => {
|
|
142
|
+
if (!enabled) {
|
|
143
|
+
return {};
|
|
144
|
+
}
|
|
145
|
+
|
|
142
146
|
const bottom = interpolateToRelativeKeyboardHeight(
|
|
143
147
|
keyboard.progress.value,
|
|
144
148
|
);
|
|
145
149
|
const translateY = interpolateToRelativeKeyboardHeight(translate.value);
|
|
146
150
|
const paddingBottom = interpolateToRelativeKeyboardHeight(padding.value);
|
|
147
|
-
const
|
|
148
|
-
const height = frame.value.height - bottomHeight;
|
|
151
|
+
const height = frame.value.height - bottom;
|
|
149
152
|
|
|
150
153
|
switch (behavior) {
|
|
151
154
|
case "height":
|
|
@@ -159,10 +162,10 @@ const KeyboardAvoidingView = forwardRef<
|
|
|
159
162
|
return {};
|
|
160
163
|
|
|
161
164
|
case "position":
|
|
162
|
-
return { bottom
|
|
165
|
+
return { bottom };
|
|
163
166
|
|
|
164
167
|
case "padding":
|
|
165
|
-
return { paddingBottom:
|
|
168
|
+
return { paddingBottom: bottom };
|
|
166
169
|
|
|
167
170
|
case "translate-with-padding":
|
|
168
171
|
return {
|
|
@@ -1,307 +0,0 @@
|
|
|
1
|
-
//
|
|
2
|
-
// KeyboardMovementObserver.swift
|
|
3
|
-
// KeyboardController
|
|
4
|
-
//
|
|
5
|
-
// Created by Kiryl Ziusko on 2.08.22.
|
|
6
|
-
// Copyright © 2022 Facebook. All rights reserved.
|
|
7
|
-
//
|
|
8
|
-
|
|
9
|
-
import Foundation
|
|
10
|
-
import UIKit
|
|
11
|
-
|
|
12
|
-
@objc(KeyboardMovementObserver)
|
|
13
|
-
public class KeyboardMovementObserver: NSObject {
|
|
14
|
-
// class members
|
|
15
|
-
var onEvent: (NSString, NSNumber, NSNumber, NSNumber, NSNumber) -> Void
|
|
16
|
-
var onNotify: (String, Any) -> Void
|
|
17
|
-
// animation
|
|
18
|
-
var onRequestAnimation: () -> Void
|
|
19
|
-
var onCancelAnimation: () -> Void
|
|
20
|
-
// progress tracker
|
|
21
|
-
private var keyboardTrackingView = KeyboardTrackingView()
|
|
22
|
-
|
|
23
|
-
private var prevKeyboardPosition = 0.0
|
|
24
|
-
private var displayLink: CADisplayLink!
|
|
25
|
-
private var interactiveKeyboardObserver: NSKeyValueObservation?
|
|
26
|
-
private var isMounted = false
|
|
27
|
-
// state variables
|
|
28
|
-
private var _keyboardHeight: CGFloat = 0.0
|
|
29
|
-
private var keyboardHeight: CGFloat {
|
|
30
|
-
get { _keyboardHeight - KeyboardAreaExtender.shared.offset }
|
|
31
|
-
set { _keyboardHeight = newValue }
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
private var duration = 0
|
|
35
|
-
private var tag: NSNumber = -1
|
|
36
|
-
private var animation: KeyboardAnimation?
|
|
37
|
-
private var didShowDeadline: Int64 = 0
|
|
38
|
-
|
|
39
|
-
@objc public init(
|
|
40
|
-
handler: @escaping (NSString, NSNumber, NSNumber, NSNumber, NSNumber) -> Void,
|
|
41
|
-
onNotify: @escaping (String, Any) -> Void,
|
|
42
|
-
onRequestAnimation: @escaping () -> Void,
|
|
43
|
-
onCancelAnimation: @escaping () -> Void
|
|
44
|
-
) {
|
|
45
|
-
onEvent = handler
|
|
46
|
-
self.onNotify = onNotify
|
|
47
|
-
self.onRequestAnimation = onRequestAnimation
|
|
48
|
-
self.onCancelAnimation = onCancelAnimation
|
|
49
|
-
|
|
50
|
-
super.init()
|
|
51
|
-
|
|
52
|
-
displayLink = CADisplayLink(target: self, selector: #selector(updateKeyboardFrame))
|
|
53
|
-
displayLink.preferredFramesPerSecond = 120 // will fallback to 60 fps for devices without Pro Motion display
|
|
54
|
-
displayLink.add(to: .main, forMode: .common)
|
|
55
|
-
displayLink.isPaused = true
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
deinit {
|
|
59
|
-
displayLink.invalidate()
|
|
60
|
-
displayLink = nil
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
@objc public func mount() {
|
|
64
|
-
if isMounted {
|
|
65
|
-
return
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
isMounted = true
|
|
69
|
-
|
|
70
|
-
NotificationCenter.default.addObserver(
|
|
71
|
-
self,
|
|
72
|
-
selector: #selector(keyboardWillDisappear),
|
|
73
|
-
name: UIResponder.keyboardWillHideNotification,
|
|
74
|
-
object: nil
|
|
75
|
-
)
|
|
76
|
-
NotificationCenter.default.addObserver(
|
|
77
|
-
self,
|
|
78
|
-
selector: #selector(keyboardWillAppear),
|
|
79
|
-
name: UIResponder.keyboardWillShowNotification,
|
|
80
|
-
object: nil
|
|
81
|
-
)
|
|
82
|
-
NotificationCenter.default.addObserver(
|
|
83
|
-
self,
|
|
84
|
-
selector: #selector(keyboardDidAppear),
|
|
85
|
-
name: UIResponder.keyboardDidShowNotification,
|
|
86
|
-
object: nil
|
|
87
|
-
)
|
|
88
|
-
NotificationCenter.default.addObserver(
|
|
89
|
-
self,
|
|
90
|
-
selector: #selector(keyboardDidDisappear),
|
|
91
|
-
name: UIResponder.keyboardDidHideNotification,
|
|
92
|
-
object: nil
|
|
93
|
-
)
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
private func setupKVObserver() {
|
|
97
|
-
guard interactiveKeyboardObserver == nil, let view = keyboardTrackingView.view else { return }
|
|
98
|
-
|
|
99
|
-
interactiveKeyboardObserver = view.observe(\.center, options: .new) { [weak self] _, change in
|
|
100
|
-
guard let self = self, let changeValue = change.newValue else { return }
|
|
101
|
-
|
|
102
|
-
self.keyboardDidMoveInteractively(changeValue: changeValue)
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
private func removeKVObserver() {
|
|
107
|
-
interactiveKeyboardObserver?.invalidate()
|
|
108
|
-
interactiveKeyboardObserver = nil
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
private func keyboardDidMoveInteractively(changeValue: CGPoint) {
|
|
112
|
-
if UIResponder.isKeyboardPreloading {
|
|
113
|
-
return
|
|
114
|
-
}
|
|
115
|
-
// if we are currently animating keyboard -> we need to ignore values from KVO
|
|
116
|
-
if !displayLink.isPaused {
|
|
117
|
-
return
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
let interactive = keyboardTrackingView.interactive(point: changeValue)
|
|
121
|
-
|
|
122
|
-
if interactive == KeyboardTrackingView.invalidPosition {
|
|
123
|
-
return
|
|
124
|
-
}
|
|
125
|
-
let position = interactive - KeyboardAreaExtender.shared.offset
|
|
126
|
-
|
|
127
|
-
if position == 0 {
|
|
128
|
-
// it will be triggered before `keyboardWillDisappear` and
|
|
129
|
-
// we don't need to trigger `onInteractive` handler for that
|
|
130
|
-
// since it will be handled in `keyboardWillDisappear` function
|
|
131
|
-
return
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
prevKeyboardPosition = position
|
|
135
|
-
|
|
136
|
-
onEvent(
|
|
137
|
-
"onKeyboardMoveInteractive",
|
|
138
|
-
position as NSNumber,
|
|
139
|
-
position / CGFloat(keyboardHeight) as NSNumber,
|
|
140
|
-
-1,
|
|
141
|
-
tag
|
|
142
|
-
)
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
@objc public func unmount() {
|
|
146
|
-
isMounted = false
|
|
147
|
-
// swiftlint:disable:next notification_center_detachment
|
|
148
|
-
NotificationCenter.default.removeObserver(self)
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
@objc func keyboardWillAppear(_ notification: Notification) {
|
|
152
|
-
guard !KeyboardEventsIgnorer.shared.shouldIgnore, !UIResponder.isKeyboardPreloading else { return }
|
|
153
|
-
|
|
154
|
-
let (duration, frame) = notification.keyboardMetaData()
|
|
155
|
-
if let keyboardFrame = frame {
|
|
156
|
-
tag = UIResponder.current.reactViewTag
|
|
157
|
-
let keyboardHeight = keyboardFrame.cgRectValue.size.height
|
|
158
|
-
self.keyboardHeight = keyboardHeight
|
|
159
|
-
self.duration = duration
|
|
160
|
-
didShowDeadline = Date.currentTimeStamp + Int64(duration)
|
|
161
|
-
|
|
162
|
-
onRequestAnimation()
|
|
163
|
-
onEvent("onKeyboardMoveStart", Float(self.keyboardHeight) as NSNumber, 1, duration as NSNumber, tag)
|
|
164
|
-
onNotify("KeyboardController::keyboardWillShow", buildEventParams(self.keyboardHeight, duration, tag))
|
|
165
|
-
|
|
166
|
-
setupKeyboardWatcher()
|
|
167
|
-
initializeAnimation(fromValue: prevKeyboardPosition, toValue: self.keyboardHeight)
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
@objc func keyboardWillDisappear(_ notification: Notification) {
|
|
172
|
-
guard !UIResponder.isKeyboardPreloading else { return }
|
|
173
|
-
let (duration, _) = notification.keyboardMetaData()
|
|
174
|
-
tag = UIResponder.current.reactViewTag
|
|
175
|
-
self.duration = duration
|
|
176
|
-
|
|
177
|
-
onRequestAnimation()
|
|
178
|
-
onEvent("onKeyboardMoveStart", 0, 0, duration as NSNumber, tag)
|
|
179
|
-
onNotify("KeyboardController::keyboardWillHide", buildEventParams(0, duration, tag))
|
|
180
|
-
|
|
181
|
-
setupKeyboardWatcher()
|
|
182
|
-
removeKVObserver()
|
|
183
|
-
initializeAnimation(fromValue: prevKeyboardPosition, toValue: 0)
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
@objc func keyboardDidAppear(_ notification: Notification) {
|
|
187
|
-
guard !UIResponder.isKeyboardPreloading else { return }
|
|
188
|
-
|
|
189
|
-
let timestamp = Date.currentTimeStamp
|
|
190
|
-
let (duration, frame) = notification.keyboardMetaData()
|
|
191
|
-
if let keyboardFrame = frame {
|
|
192
|
-
let (position, _) = keyboardTrackingView.view.frameTransitionInWindow
|
|
193
|
-
let keyboardHeight = keyboardFrame.cgRectValue.size.height
|
|
194
|
-
tag = UIResponder.current.reactViewTag
|
|
195
|
-
self.keyboardHeight = keyboardHeight
|
|
196
|
-
|
|
197
|
-
guard !KeyboardEventsIgnorer.shared.shouldIgnore else {
|
|
198
|
-
KeyboardEventsIgnorer.shared.shouldIgnoreKeyboardEvents = false
|
|
199
|
-
return
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
// if the event is caught in between it's highly likely that it could be a "resize" event
|
|
203
|
-
// so we just read actual keyboard frame value in this case
|
|
204
|
-
let height = timestamp >= didShowDeadline ? self.keyboardHeight : position - KeyboardAreaExtender.shared.offset
|
|
205
|
-
// always limit progress to the maximum possible value
|
|
206
|
-
let progress = min(height / self.keyboardHeight, 1.0)
|
|
207
|
-
|
|
208
|
-
onCancelAnimation()
|
|
209
|
-
onEvent("onKeyboardMoveEnd", height as NSNumber, progress as NSNumber, duration as NSNumber, tag)
|
|
210
|
-
onNotify("KeyboardController::keyboardDidShow", buildEventParams(height, duration, tag))
|
|
211
|
-
|
|
212
|
-
removeKeyboardWatcher()
|
|
213
|
-
setupKVObserver()
|
|
214
|
-
animation = nil
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
@objc func keyboardDidDisappear(_ notification: Notification) {
|
|
219
|
-
guard !UIResponder.isKeyboardPreloading else { return }
|
|
220
|
-
let (duration, _) = notification.keyboardMetaData()
|
|
221
|
-
tag = UIResponder.current.reactViewTag
|
|
222
|
-
|
|
223
|
-
onCancelAnimation()
|
|
224
|
-
onEvent("onKeyboardMoveEnd", 0 as NSNumber, 0, duration as NSNumber, tag)
|
|
225
|
-
onNotify("KeyboardController::keyboardDidHide", buildEventParams(0, duration, tag))
|
|
226
|
-
|
|
227
|
-
removeKeyboardWatcher()
|
|
228
|
-
animation = nil
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
@objc func setupKeyboardWatcher() {
|
|
232
|
-
// sometimes `will` events can be called multiple times.
|
|
233
|
-
// To avoid double re-creation of listener we are adding this condition
|
|
234
|
-
// (if active link is present, then no need to re-setup a listener)
|
|
235
|
-
if !displayLink.isPaused {
|
|
236
|
-
return
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
displayLink.isPaused = false
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
@objc func removeKeyboardWatcher() {
|
|
243
|
-
displayLink.isPaused = true
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
func initializeAnimation(fromValue: Double, toValue: Double) {
|
|
247
|
-
for key in ["position", "opacity"] {
|
|
248
|
-
if let keyboardAnimation = keyboardTrackingView.view?.layer.presentation()?.animation(forKey: key) {
|
|
249
|
-
if let springAnimation = keyboardAnimation as? CASpringAnimation {
|
|
250
|
-
animation = SpringAnimation(animation: springAnimation, fromValue: fromValue, toValue: toValue)
|
|
251
|
-
} else if let basicAnimation = keyboardAnimation as? CABasicAnimation {
|
|
252
|
-
animation = TimingAnimation(animation: basicAnimation, fromValue: fromValue, toValue: toValue)
|
|
253
|
-
}
|
|
254
|
-
return
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
@objc func updateKeyboardFrame(link: CADisplayLink) {
|
|
260
|
-
if keyboardTrackingView.view == nil {
|
|
261
|
-
return
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
let (visibleKeyboardHeight, keyboardFrameY) = keyboardTrackingView.view.frameTransitionInWindow
|
|
265
|
-
var keyboardPosition = visibleKeyboardHeight - KeyboardAreaExtender.shared.offset
|
|
266
|
-
|
|
267
|
-
if keyboardPosition == prevKeyboardPosition || keyboardFrameY == 0 {
|
|
268
|
-
return
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
if animation == nil {
|
|
272
|
-
initializeAnimation(fromValue: prevKeyboardPosition, toValue: keyboardHeight)
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
prevKeyboardPosition = keyboardPosition
|
|
276
|
-
|
|
277
|
-
if let animation = animation {
|
|
278
|
-
let baseDuration = animation.timingAt(value: keyboardPosition)
|
|
279
|
-
|
|
280
|
-
#if targetEnvironment(simulator)
|
|
281
|
-
// on iOS simulator we can not use static interval
|
|
282
|
-
// (from my observation from frame to frame we may have different delays)
|
|
283
|
-
// so for now we use approximation - we add a difference as
|
|
284
|
-
// beginTime - keyboardEventTime (but only in 0..0.016 range)
|
|
285
|
-
// and it gives satisfactory results (better than static delays)
|
|
286
|
-
let duration = baseDuration + animation.diff
|
|
287
|
-
#else
|
|
288
|
-
// 2 frames because we read previous frame, but need to calculate the next frame
|
|
289
|
-
let duration = baseDuration + link.duration * 2
|
|
290
|
-
#endif
|
|
291
|
-
|
|
292
|
-
let position = CGFloat(animation.valueAt(time: duration))
|
|
293
|
-
// handles a case when final frame has final destination (i. e. 0 or 291)
|
|
294
|
-
// but CASpringAnimation can never get to this final destination
|
|
295
|
-
let race: (CGFloat, CGFloat) -> CGFloat = animation.isIncreasing ? max : min
|
|
296
|
-
keyboardPosition = race(position, keyboardPosition)
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
onEvent(
|
|
300
|
-
"onKeyboardMove",
|
|
301
|
-
keyboardPosition as NSNumber,
|
|
302
|
-
keyboardPosition / CGFloat(keyboardHeight) as NSNumber,
|
|
303
|
-
duration as NSNumber,
|
|
304
|
-
tag
|
|
305
|
-
)
|
|
306
|
-
}
|
|
307
|
-
}
|
|
File without changes
|
|
File without changes
|