react-native-keyboard-controller 1.9.3 → 1.9.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/README.md +2 -2
- package/android/build.gradle +3 -0
- package/android/src/main/java/com/reactnativekeyboardcontroller/listeners/{FocusedInputLayoutObserver.kt → FocusedInputObserver.kt} +1 -1
- package/android/src/main/java/com/reactnativekeyboardcontroller/listeners/KeyboardAnimationCallback.kt +77 -56
- package/ios/KeyboardController.xcodeproj/project.pbxproj +4 -4
- package/ios/observers/{FocusedInputLayoutObserver.swift → FocusedInputObserver.swift} +3 -3
- package/ios/views/KeyboardControllerView.mm +2 -2
- package/ios/views/KeyboardControllerViewManager.swift +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -22,10 +22,10 @@ Keyboard manager which works in identical way on both iOS and Android.
|
|
|
22
22
|
|
|
23
23
|
Install `react-native-keyboard-controller` package from npm:
|
|
24
24
|
|
|
25
|
-
```
|
|
25
|
+
```shell
|
|
26
26
|
yarn add react-native-keyboard-controller
|
|
27
27
|
# or
|
|
28
|
-
|
|
28
|
+
npm install react-native-keyboard-controller --save
|
|
29
29
|
```
|
|
30
30
|
|
|
31
31
|
## Documentation
|
package/android/build.gradle
CHANGED
|
@@ -43,6 +43,9 @@ android {
|
|
|
43
43
|
def agpVersion = com.android.Version.ANDROID_GRADLE_PLUGIN_VERSION
|
|
44
44
|
if (agpVersion.tokenize('.')[0].toInteger() >= 7) {
|
|
45
45
|
namespace "com.reactnativekeyboardcontroller"
|
|
46
|
+
buildFeatures {
|
|
47
|
+
buildConfig true
|
|
48
|
+
}
|
|
46
49
|
}
|
|
47
50
|
|
|
48
51
|
compileSdkVersion getExtOrIntegerDefault('compileSdkVersion')
|
|
@@ -22,7 +22,7 @@ val noFocusedInputEvent = FocusedInputLayoutChangedEventData(
|
|
|
22
22
|
target = -1,
|
|
23
23
|
)
|
|
24
24
|
|
|
25
|
-
class
|
|
25
|
+
class FocusedInputObserver(val view: ReactViewGroup, private val context: ThemedReactContext?) {
|
|
26
26
|
// constructor variables
|
|
27
27
|
private val surfaceId = UIManagerHelper.getSurfaceId(view)
|
|
28
28
|
|
|
@@ -41,6 +41,7 @@ class KeyboardAnimationCallback(
|
|
|
41
41
|
private var isTransitioning = false
|
|
42
42
|
private var duration = 0
|
|
43
43
|
private var viewTagFocused = -1
|
|
44
|
+
private var animation: ValueAnimator? = null
|
|
44
45
|
|
|
45
46
|
// listeners
|
|
46
47
|
private val focusListener = OnGlobalFocusChangeListener { oldFocus, newFocus ->
|
|
@@ -83,7 +84,7 @@ class KeyboardAnimationCallback(
|
|
|
83
84
|
}
|
|
84
85
|
}
|
|
85
86
|
}
|
|
86
|
-
private var layoutObserver:
|
|
87
|
+
private var layoutObserver: FocusedInputObserver? = null
|
|
87
88
|
|
|
88
89
|
init {
|
|
89
90
|
require(persistentInsetTypes and deferredInsetTypes == 0) {
|
|
@@ -91,7 +92,7 @@ class KeyboardAnimationCallback(
|
|
|
91
92
|
" same WindowInsetsCompat.Type values"
|
|
92
93
|
}
|
|
93
94
|
|
|
94
|
-
layoutObserver =
|
|
95
|
+
layoutObserver = FocusedInputObserver(view = view, context = context)
|
|
95
96
|
view.viewTreeObserver.addOnGlobalFocusChangeListener(focusListener)
|
|
96
97
|
}
|
|
97
98
|
|
|
@@ -104,10 +105,6 @@ class KeyboardAnimationCallback(
|
|
|
104
105
|
* behavior should be consistent across all versions of platform. To level the difference we
|
|
105
106
|
* have to implement `onApplyWindowInsets` listener and simulate onStart/onProgress/onEnd
|
|
106
107
|
* events when keyboard changes its size.
|
|
107
|
-
* In the method below we fully recreate the logic that is implemented on old android versions:
|
|
108
|
-
* - we dispatch `keyboardWillShow` (onStart);
|
|
109
|
-
* - we dispatch change height/progress as animated values (onProgress);
|
|
110
|
-
* - we dispatch `keyboardDidShow` (onEnd).
|
|
111
108
|
*/
|
|
112
109
|
override fun onApplyWindowInsets(v: View, insets: WindowInsetsCompat): WindowInsetsCompat {
|
|
113
110
|
val keyboardHeight = getCurrentKeyboardHeight()
|
|
@@ -133,57 +130,9 @@ class KeyboardAnimationCallback(
|
|
|
133
130
|
val isKeyboardSizeEqual = this.persistentKeyboardHeight == keyboardHeight
|
|
134
131
|
|
|
135
132
|
if (isKeyboardFullyVisible && !isKeyboardSizeEqual && Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
|
133
|
+
Log.i(TAG, "onApplyWindowInsets: ${this.persistentKeyboardHeight} -> $keyboardHeight")
|
|
136
134
|
layoutObserver?.syncUpLayout()
|
|
137
|
-
this.
|
|
138
|
-
context.dispatchEvent(
|
|
139
|
-
view.id,
|
|
140
|
-
KeyboardTransitionEvent(
|
|
141
|
-
surfaceId,
|
|
142
|
-
view.id,
|
|
143
|
-
"topKeyboardMoveStart",
|
|
144
|
-
keyboardHeight,
|
|
145
|
-
1.0,
|
|
146
|
-
DEFAULT_ANIMATION_TIME,
|
|
147
|
-
viewTagFocused,
|
|
148
|
-
),
|
|
149
|
-
)
|
|
150
|
-
|
|
151
|
-
val animation =
|
|
152
|
-
ValueAnimator.ofFloat(this.persistentKeyboardHeight.toFloat(), keyboardHeight.toFloat())
|
|
153
|
-
animation.addUpdateListener { animator ->
|
|
154
|
-
val toValue = animator.animatedValue as Float
|
|
155
|
-
context.dispatchEvent(
|
|
156
|
-
view.id,
|
|
157
|
-
KeyboardTransitionEvent(
|
|
158
|
-
surfaceId,
|
|
159
|
-
view.id,
|
|
160
|
-
"topKeyboardMove",
|
|
161
|
-
toValue.toDouble(),
|
|
162
|
-
toValue.toDouble() / keyboardHeight,
|
|
163
|
-
DEFAULT_ANIMATION_TIME,
|
|
164
|
-
viewTagFocused,
|
|
165
|
-
),
|
|
166
|
-
)
|
|
167
|
-
}
|
|
168
|
-
animation.doOnEnd {
|
|
169
|
-
this.emitEvent("KeyboardController::keyboardDidShow", getEventParams(keyboardHeight))
|
|
170
|
-
context.dispatchEvent(
|
|
171
|
-
view.id,
|
|
172
|
-
KeyboardTransitionEvent(
|
|
173
|
-
surfaceId,
|
|
174
|
-
view.id,
|
|
175
|
-
"topKeyboardMoveEnd",
|
|
176
|
-
keyboardHeight,
|
|
177
|
-
1.0,
|
|
178
|
-
DEFAULT_ANIMATION_TIME,
|
|
179
|
-
viewTagFocused,
|
|
180
|
-
),
|
|
181
|
-
)
|
|
182
|
-
}
|
|
183
|
-
animation.setDuration(DEFAULT_ANIMATION_TIME.toLong()).startDelay = 0
|
|
184
|
-
animation.start()
|
|
185
|
-
|
|
186
|
-
this.persistentKeyboardHeight = keyboardHeight
|
|
135
|
+
this.onKeyboardResized(keyboardHeight)
|
|
187
136
|
}
|
|
188
137
|
|
|
189
138
|
return insets
|
|
@@ -320,6 +269,78 @@ class KeyboardAnimationCallback(
|
|
|
320
269
|
layoutObserver?.destroy()
|
|
321
270
|
}
|
|
322
271
|
|
|
272
|
+
/*
|
|
273
|
+
* In the method below we recreate the logic that used when keyboard appear/disappear:
|
|
274
|
+
* - we dispatch `keyboardWillShow` (onStart);
|
|
275
|
+
* - we dispatch change height/progress as animated values (onProgress);
|
|
276
|
+
* - we dispatch `keyboardDidShow` (onEnd).
|
|
277
|
+
*/
|
|
278
|
+
private fun onKeyboardResized(keyboardHeight: Double) {
|
|
279
|
+
if (this.animation?.isRunning == true) {
|
|
280
|
+
Log.i(TAG, "onKeyboardResized -> cancelling animation that is in progress")
|
|
281
|
+
// if animation is in progress, then we are:
|
|
282
|
+
// - removing listeners (update, onEnd)
|
|
283
|
+
// - updating `persistentKeyboardHeight` to latest animated value
|
|
284
|
+
// - cancelling animation to free up CPU resources
|
|
285
|
+
this.animation?.removeAllListeners()
|
|
286
|
+
this.persistentKeyboardHeight = (this.animation?.animatedValue as Float).toDouble()
|
|
287
|
+
this.animation?.cancel()
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
this.emitEvent("KeyboardController::keyboardWillShow", getEventParams(keyboardHeight))
|
|
291
|
+
context.dispatchEvent(
|
|
292
|
+
view.id,
|
|
293
|
+
KeyboardTransitionEvent(
|
|
294
|
+
surfaceId,
|
|
295
|
+
view.id,
|
|
296
|
+
"topKeyboardMoveStart",
|
|
297
|
+
keyboardHeight,
|
|
298
|
+
1.0,
|
|
299
|
+
DEFAULT_ANIMATION_TIME,
|
|
300
|
+
viewTagFocused,
|
|
301
|
+
),
|
|
302
|
+
)
|
|
303
|
+
|
|
304
|
+
val animation =
|
|
305
|
+
ValueAnimator.ofFloat(this.persistentKeyboardHeight.toFloat(), keyboardHeight.toFloat())
|
|
306
|
+
animation.addUpdateListener { animator ->
|
|
307
|
+
val toValue = animator.animatedValue as Float
|
|
308
|
+
context.dispatchEvent(
|
|
309
|
+
view.id,
|
|
310
|
+
KeyboardTransitionEvent(
|
|
311
|
+
surfaceId,
|
|
312
|
+
view.id,
|
|
313
|
+
"topKeyboardMove",
|
|
314
|
+
toValue.toDouble(),
|
|
315
|
+
toValue.toDouble() / keyboardHeight,
|
|
316
|
+
DEFAULT_ANIMATION_TIME,
|
|
317
|
+
viewTagFocused,
|
|
318
|
+
),
|
|
319
|
+
)
|
|
320
|
+
}
|
|
321
|
+
animation.doOnEnd {
|
|
322
|
+
this.emitEvent("KeyboardController::keyboardDidShow", getEventParams(keyboardHeight))
|
|
323
|
+
context.dispatchEvent(
|
|
324
|
+
view.id,
|
|
325
|
+
KeyboardTransitionEvent(
|
|
326
|
+
surfaceId,
|
|
327
|
+
view.id,
|
|
328
|
+
"topKeyboardMoveEnd",
|
|
329
|
+
keyboardHeight,
|
|
330
|
+
1.0,
|
|
331
|
+
DEFAULT_ANIMATION_TIME,
|
|
332
|
+
viewTagFocused,
|
|
333
|
+
),
|
|
334
|
+
)
|
|
335
|
+
this.animation = null
|
|
336
|
+
}
|
|
337
|
+
animation.setDuration(DEFAULT_ANIMATION_TIME.toLong()).startDelay = 0
|
|
338
|
+
animation.start()
|
|
339
|
+
|
|
340
|
+
this.animation = animation
|
|
341
|
+
this.persistentKeyboardHeight = keyboardHeight
|
|
342
|
+
}
|
|
343
|
+
|
|
323
344
|
private fun isKeyboardVisible(): Boolean {
|
|
324
345
|
val insets = ViewCompat.getRootWindowInsets(view)
|
|
325
346
|
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
/* Begin PBXBuildFile section */
|
|
10
10
|
0807071E2A34807B00C05A19 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0807071D2A34807B00C05A19 /* Extensions.swift */; };
|
|
11
11
|
084AEEC62ACF49A8001A3069 /* FocusedInputLayoutChangedEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = 084AEEC52ACF49A8001A3069 /* FocusedInputLayoutChangedEvent.m */; };
|
|
12
|
-
084AEEC82ACF4AB2001A3069 /*
|
|
12
|
+
084AEEC82ACF4AB2001A3069 /* FocusedInputObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 084AEEC72ACF4AB2001A3069 /* FocusedInputObserver.swift */; };
|
|
13
13
|
F333F8D428996B8D0015B05F /* KeyboardControllerView.mm in Sources */ = {isa = PBXBuildFile; fileRef = F333F8D228996B8D0015B05F /* KeyboardControllerView.mm */; };
|
|
14
14
|
F359D34F28133C26000B6AFE /* KeyboardControllerModule.mm in Sources */ = {isa = PBXBuildFile; fileRef = F359D34E28133C26000B6AFE /* KeyboardControllerModule.mm */; };
|
|
15
15
|
F3626A0728B3FE760021B2D9 /* KeyboardMovementObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3626A0628B3FE760021B2D9 /* KeyboardMovementObserver.swift */; };
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
0807071D2A34807B00C05A19 /* Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Extensions.swift; sourceTree = "<group>"; };
|
|
34
34
|
084AEEC22ACF479A001A3069 /* FocusedInputLayoutChangedEvent.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FocusedInputLayoutChangedEvent.h; sourceTree = "<group>"; };
|
|
35
35
|
084AEEC52ACF49A8001A3069 /* FocusedInputLayoutChangedEvent.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FocusedInputLayoutChangedEvent.m; sourceTree = "<group>"; };
|
|
36
|
-
084AEEC72ACF4AB2001A3069 /*
|
|
36
|
+
084AEEC72ACF4AB2001A3069 /* FocusedInputObserver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FocusedInputObserver.swift; sourceTree = "<group>"; };
|
|
37
37
|
134814201AA4EA6300B7C361 /* libKeyboardController.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libKeyboardController.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
|
38
38
|
B3E7B5891CC2AC0600A0062D /* KeyboardControllerViewManager.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = KeyboardControllerViewManager.mm; sourceTree = "<group>"; };
|
|
39
39
|
F333F8D128996B1C0015B05F /* KeyboardControllerView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KeyboardControllerView.h; sourceTree = "<group>"; };
|
|
@@ -73,7 +73,7 @@
|
|
|
73
73
|
isa = PBXGroup;
|
|
74
74
|
children = (
|
|
75
75
|
F3626A0628B3FE760021B2D9 /* KeyboardMovementObserver.swift */,
|
|
76
|
-
084AEEC72ACF4AB2001A3069 /*
|
|
76
|
+
084AEEC72ACF4AB2001A3069 /* FocusedInputObserver.swift */,
|
|
77
77
|
);
|
|
78
78
|
path = observers;
|
|
79
79
|
sourceTree = "<group>";
|
|
@@ -172,7 +172,7 @@
|
|
|
172
172
|
F3626A0728B3FE760021B2D9 /* KeyboardMovementObserver.swift in Sources */,
|
|
173
173
|
0807071E2A34807B00C05A19 /* Extensions.swift in Sources */,
|
|
174
174
|
F359D34F28133C26000B6AFE /* KeyboardControllerModule.mm in Sources */,
|
|
175
|
-
084AEEC82ACF4AB2001A3069 /*
|
|
175
|
+
084AEEC82ACF4AB2001A3069 /* FocusedInputObserver.swift in Sources */,
|
|
176
176
|
F4FF95D7245B92E800C19C63 /* KeyboardControllerViewManager.swift in Sources */,
|
|
177
177
|
F333F8D428996B8D0015B05F /* KeyboardControllerView.mm in Sources */,
|
|
178
178
|
F3F50669289E653B003091D6 /* KeyboardMoveEvent.m in Sources */,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
//
|
|
2
|
-
//
|
|
2
|
+
// FocusedInputObserver.swift
|
|
3
3
|
// KeyboardController
|
|
4
4
|
//
|
|
5
5
|
// Created by Kiryl Ziusko on 05/10/2023.
|
|
@@ -21,8 +21,8 @@ let noFocusedInputEvent: [String: Any] = [
|
|
|
21
21
|
],
|
|
22
22
|
]
|
|
23
23
|
|
|
24
|
-
@objc(
|
|
25
|
-
public class
|
|
24
|
+
@objc(FocusedInputObserver)
|
|
25
|
+
public class FocusedInputObserver: NSObject {
|
|
26
26
|
// class members
|
|
27
27
|
var onEvent: (NSDictionary) -> Void
|
|
28
28
|
// state variables
|
|
@@ -31,7 +31,7 @@ using namespace facebook::react;
|
|
|
31
31
|
|
|
32
32
|
@implementation KeyboardControllerView {
|
|
33
33
|
KeyboardMovementObserver *keyboardObserver;
|
|
34
|
-
|
|
34
|
+
FocusedInputObserver *inputObserver;
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
+ (ComponentDescriptorProvider)componentDescriptorProvider
|
|
@@ -45,7 +45,7 @@ using namespace facebook::react;
|
|
|
45
45
|
static const auto defaultProps = std::make_shared<const KeyboardControllerViewProps>();
|
|
46
46
|
_props = defaultProps;
|
|
47
47
|
|
|
48
|
-
inputObserver = [[
|
|
48
|
+
inputObserver = [[FocusedInputObserver alloc] initWithHandler:^(NSDictionary *event) {
|
|
49
49
|
if (self->_eventEmitter) {
|
|
50
50
|
int target = [event[@"target"] integerValue];
|
|
51
51
|
double absoluteY = [event[@"layout"][@"absoluteY"] doubleValue];
|
|
@@ -12,7 +12,7 @@ class KeyboardControllerViewManager: RCTViewManager {
|
|
|
12
12
|
class KeyboardControllerView: UIView {
|
|
13
13
|
// internal variables
|
|
14
14
|
private var keyboardObserver: KeyboardMovementObserver?
|
|
15
|
-
private var inputObserver:
|
|
15
|
+
private var inputObserver: FocusedInputObserver?
|
|
16
16
|
private var eventDispatcher: RCTEventDispatcherProtocol
|
|
17
17
|
private var bridge: RCTBridge
|
|
18
18
|
// react callbacks
|
|
@@ -35,7 +35,7 @@ class KeyboardControllerView: UIView {
|
|
|
35
35
|
self.bridge = bridge
|
|
36
36
|
eventDispatcher = bridge.eventDispatcher()
|
|
37
37
|
super.init(frame: frame)
|
|
38
|
-
inputObserver =
|
|
38
|
+
inputObserver = FocusedInputObserver(handler: onInput)
|
|
39
39
|
keyboardObserver = KeyboardMovementObserver(handler: onEvent, onNotify: onNotify)
|
|
40
40
|
}
|
|
41
41
|
|
package/package.json
CHANGED