react-native-keyboard-controller 1.13.4 → 1.14.0
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 +1 -0
- package/android/src/fabric/java/com/reactnativekeyboardcontroller/KeyboardControllerModule.kt +5 -3
- package/android/src/fabric/java/com/reactnativekeyboardcontroller/KeyboardControllerViewManager.kt +19 -20
- package/android/src/fabric/java/com/reactnativekeyboardcontroller/KeyboardGestureAreaViewManager.kt +22 -12
- package/android/src/fabric/java/com/reactnativekeyboardcontroller/OverKeyboardViewManager.kt +40 -0
- package/android/src/fabric/java/com/reactnativekeyboardcontroller/StatusBarManagerCompatModule.kt +7 -3
- package/android/src/main/java/com/reactnativekeyboardcontroller/KeyboardControllerPackage.kt +33 -27
- package/android/src/main/java/com/reactnativekeyboardcontroller/events/FocusedInputLayoutChangedEvent.kt +16 -15
- package/android/src/main/java/com/reactnativekeyboardcontroller/events/FocusedInputSelectionChangedEvent.kt +25 -24
- package/android/src/main/java/com/reactnativekeyboardcontroller/events/FocusedInputTextChangedEvent.kt +4 -3
- package/android/src/main/java/com/reactnativekeyboardcontroller/events/KeyboardTransitionEvent.kt +7 -6
- package/android/src/main/java/com/reactnativekeyboardcontroller/extensions/Context.kt +38 -0
- package/android/src/main/java/com/reactnativekeyboardcontroller/extensions/EditText.kt +78 -58
- package/android/src/main/java/com/reactnativekeyboardcontroller/extensions/ReactContext.kt +9 -4
- package/android/src/main/java/com/reactnativekeyboardcontroller/extensions/ThemedReactContext.kt +10 -3
- package/android/src/main/java/com/reactnativekeyboardcontroller/extensions/View.kt +10 -8
- package/android/src/main/java/com/reactnativekeyboardcontroller/interactive/KeyboardAnimationController.kt +65 -60
- package/android/src/main/java/com/reactnativekeyboardcontroller/interactive/interpolators/Interpolator.kt +6 -1
- package/android/src/main/java/com/reactnativekeyboardcontroller/interactive/interpolators/IosInterpolator.kt +4 -2
- package/android/src/main/java/com/reactnativekeyboardcontroller/interactive/interpolators/LinearInterpolator.kt +1 -3
- package/android/src/main/java/com/reactnativekeyboardcontroller/listeners/FocusedInputObserver.kt +62 -58
- package/android/src/main/java/com/reactnativekeyboardcontroller/listeners/KeyboardAnimationCallback.kt +47 -41
- package/android/src/main/java/com/reactnativekeyboardcontroller/listeners/WindowDimensionListener.kt +13 -7
- package/android/src/main/java/com/reactnativekeyboardcontroller/log/Logger.kt +10 -2
- package/android/src/main/java/com/reactnativekeyboardcontroller/managers/KeyboardControllerViewManagerImpl.kt +35 -24
- package/android/src/main/java/com/reactnativekeyboardcontroller/managers/KeyboardGestureAreaViewManagerImpl.kt +21 -8
- package/android/src/main/java/com/reactnativekeyboardcontroller/managers/OverKeyboardViewManagerImpl.kt +27 -0
- package/android/src/main/java/com/reactnativekeyboardcontroller/modal/ModalAttachedWatcher.kt +14 -12
- package/android/src/main/java/com/reactnativekeyboardcontroller/modules/KeyboardControllerModuleImpl.kt +8 -8
- package/android/src/main/java/com/reactnativekeyboardcontroller/modules/StatusBarManagerCompatModuleImpl.kt +7 -2
- package/android/src/main/java/com/reactnativekeyboardcontroller/traversal/FocusedInputHolder.kt +1 -3
- package/android/src/main/java/com/reactnativekeyboardcontroller/traversal/ViewHierarchyNavigator.kt +19 -13
- package/android/src/main/java/com/reactnativekeyboardcontroller/ui/FrameScheduler.kt +11 -8
- package/android/src/main/java/com/reactnativekeyboardcontroller/views/EdgeToEdgeReactViewGroup.kt +22 -17
- package/android/src/main/java/com/reactnativekeyboardcontroller/views/KeyboardGestureAreaReactViewGroup.kt +23 -14
- package/android/src/main/java/com/reactnativekeyboardcontroller/views/overlay/OverKeyboardHostShadowNode.kt +30 -0
- package/android/src/main/java/com/reactnativekeyboardcontroller/views/overlay/OverKeyboardViewGroup.kt +185 -0
- package/android/src/paper/java/com/reactnativekeyboardcontroller/KeyboardControllerModule.kt +3 -1
- package/android/src/paper/java/com/reactnativekeyboardcontroller/KeyboardControllerViewManager.kt +19 -10
- package/android/src/paper/java/com/reactnativekeyboardcontroller/KeyboardGestureAreaViewManager.kt +21 -8
- package/android/src/paper/java/com/reactnativekeyboardcontroller/OverKeyboardViewManager.kt +33 -0
- package/android/src/paper/java/com/reactnativekeyboardcontroller/StatusBarManagerCompatModule.kt +7 -3
- package/android/src/test/java/com/reactnativekeyboardcontroller/traversal/ViewHierarchyNavigatorTest.kt +30 -21
- package/ios/KeyboardController-Bridging-Header.h +1 -0
- package/ios/extensions/UIResponder.swift +0 -3
- package/ios/extensions/UIWindow.swift +48 -0
- package/ios/views/OverKeyboardViewManager.h +29 -0
- package/ios/views/OverKeyboardViewManager.mm +220 -0
- package/jest/index.js +1 -0
- package/lib/commonjs/bindings.js +2 -1
- package/lib/commonjs/bindings.js.map +1 -1
- package/lib/commonjs/bindings.native.js +2 -1
- package/lib/commonjs/bindings.native.js.map +1 -1
- package/lib/commonjs/components/KeyboardAwareScrollView/index.js +2 -1
- package/lib/commonjs/components/KeyboardAwareScrollView/index.js.map +1 -1
- package/lib/commonjs/components/KeyboardToolbar/index.js +5 -3
- package/lib/commonjs/components/KeyboardToolbar/index.js.map +1 -1
- package/lib/commonjs/index.js +9 -1
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/specs/OverKeyboardViewNativeComponent.js +10 -0
- package/lib/commonjs/specs/OverKeyboardViewNativeComponent.js.map +1 -0
- package/lib/commonjs/types.js.map +1 -1
- package/lib/commonjs/views/OverKeyboardView/index.js +43 -0
- package/lib/commonjs/views/OverKeyboardView/index.js.map +1 -0
- package/lib/commonjs/views/index.js +14 -0
- package/lib/commonjs/views/index.js.map +1 -0
- package/lib/module/bindings.js +1 -0
- package/lib/module/bindings.js.map +1 -1
- package/lib/module/bindings.native.js +1 -0
- package/lib/module/bindings.native.js.map +1 -1
- package/lib/module/components/KeyboardAwareScrollView/index.js +2 -1
- package/lib/module/components/KeyboardAwareScrollView/index.js.map +1 -1
- package/lib/module/components/KeyboardToolbar/index.js +5 -3
- package/lib/module/components/KeyboardToolbar/index.js.map +1 -1
- package/lib/module/index.js +1 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/specs/OverKeyboardViewNativeComponent.js +3 -0
- package/lib/module/specs/OverKeyboardViewNativeComponent.js.map +1 -0
- package/lib/module/types.js.map +1 -1
- package/lib/module/views/OverKeyboardView/index.js +35 -0
- package/lib/module/views/OverKeyboardView/index.js.map +1 -0
- package/lib/module/views/index.js +2 -0
- package/lib/module/views/index.js.map +1 -0
- package/lib/typescript/bindings.d.ts +2 -1
- package/lib/typescript/bindings.native.d.ts +2 -1
- package/lib/typescript/components/KeyboardAwareScrollView/index.d.ts +4 -0
- package/lib/typescript/components/KeyboardToolbar/index.d.ts +2 -2
- package/lib/typescript/index.d.ts +1 -0
- package/lib/typescript/specs/OverKeyboardViewNativeComponent.d.ts +7 -0
- package/lib/typescript/types.d.ts +4 -1
- package/lib/typescript/views/OverKeyboardView/index.d.ts +5 -0
- package/lib/typescript/views/index.d.ts +1 -0
- package/package.json +8 -3
- package/src/bindings.native.ts +3 -0
- package/src/bindings.ts +3 -0
- package/src/components/KeyboardAwareScrollView/index.tsx +5 -2
- package/src/components/KeyboardToolbar/index.tsx +7 -3
- package/src/index.ts +1 -0
- package/src/specs/OverKeyboardViewNativeComponent.ts +12 -0
- package/src/types.ts +4 -0
- package/src/views/OverKeyboardView/index.tsx +43 -0
- package/src/views/index.ts +1 -0
- package/ios/.clang-format +0 -90
- package/ios/.swiftformat +0 -5
- package/ios/.swiftlint.yml +0 -14
|
@@ -18,16 +18,18 @@ fun View.requestApplyInsetsWhenAttached() {
|
|
|
18
18
|
requestApplyInsets()
|
|
19
19
|
} else {
|
|
20
20
|
// We're not attached to the hierarchy, add a listener to request when we are
|
|
21
|
-
addOnAttachStateChangeListener(
|
|
22
|
-
|
|
23
|
-
v
|
|
24
|
-
|
|
25
|
-
|
|
21
|
+
addOnAttachStateChangeListener(
|
|
22
|
+
object : View.OnAttachStateChangeListener {
|
|
23
|
+
override fun onViewAttachedToWindow(v: View) {
|
|
24
|
+
v.removeOnAttachStateChangeListener(this)
|
|
25
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) {
|
|
26
|
+
v.requestApplyInsets()
|
|
27
|
+
}
|
|
26
28
|
}
|
|
27
|
-
}
|
|
28
29
|
|
|
29
|
-
|
|
30
|
-
|
|
30
|
+
override fun onViewDetachedFromWindow(v: View) = Unit
|
|
31
|
+
},
|
|
32
|
+
)
|
|
31
33
|
}
|
|
32
34
|
}
|
|
33
35
|
|
|
@@ -73,7 +73,8 @@ internal class KeyboardAnimationController {
|
|
|
73
73
|
}
|
|
74
74
|
|
|
75
75
|
// Keep track of the IME insets, and the IME visibility, at the start of the request
|
|
76
|
-
isImeShownAtStart = ViewCompat
|
|
76
|
+
isImeShownAtStart = ViewCompat
|
|
77
|
+
.getRootWindowInsets(view)
|
|
77
78
|
?.isVisible(WindowInsetsCompat.Type.ime()) == true
|
|
78
79
|
|
|
79
80
|
// Create a cancellation signal, which we pass to controlWindowInsetsAnimation() below
|
|
@@ -114,7 +115,10 @@ internal class KeyboardAnimationController {
|
|
|
114
115
|
* @param view The view which is triggering this request
|
|
115
116
|
* @param velocityY the velocity of the touch gesture which caused this call
|
|
116
117
|
*/
|
|
117
|
-
fun startAndFling(
|
|
118
|
+
fun startAndFling(
|
|
119
|
+
view: View,
|
|
120
|
+
velocityY: Float,
|
|
121
|
+
) = startControlRequest(view) {
|
|
118
122
|
animateToFinish(velocityY)
|
|
119
123
|
}
|
|
120
124
|
|
|
@@ -127,11 +131,12 @@ internal class KeyboardAnimationController {
|
|
|
127
131
|
* @return the amount of [dy] consumed by the inset animation, in pixels
|
|
128
132
|
*/
|
|
129
133
|
fun insetBy(dy: Int): Int {
|
|
130
|
-
val controller =
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
"
|
|
134
|
-
|
|
134
|
+
val controller =
|
|
135
|
+
insetsAnimationController
|
|
136
|
+
?: throw IllegalStateException(
|
|
137
|
+
"Current WindowInsetsAnimationController is null." +
|
|
138
|
+
"This should only be called if isAnimationInProgress() returns true",
|
|
139
|
+
)
|
|
135
140
|
|
|
136
141
|
InteractiveKeyboardProvider.isInteractive = true
|
|
137
142
|
// Call updateInsetTo() with the new inset value
|
|
@@ -147,11 +152,12 @@ internal class KeyboardAnimationController {
|
|
|
147
152
|
* @return the distance moved by the inset animation, in pixels
|
|
148
153
|
*/
|
|
149
154
|
fun insetTo(inset: Int): Int {
|
|
150
|
-
val controller =
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
"
|
|
154
|
-
|
|
155
|
+
val controller =
|
|
156
|
+
insetsAnimationController
|
|
157
|
+
?: throw IllegalStateException(
|
|
158
|
+
"Current WindowInsetsAnimationController is null." +
|
|
159
|
+
"This should only be called if isAnimationInProgress() returns true",
|
|
160
|
+
)
|
|
155
161
|
|
|
156
162
|
val hiddenBottom = controller.hiddenStateInsets.bottom
|
|
157
163
|
val shownBottom = controller.shownStateInsets.bottom
|
|
@@ -182,23 +188,17 @@ internal class KeyboardAnimationController {
|
|
|
182
188
|
/**
|
|
183
189
|
* Return `true` if an inset animation is in progress.
|
|
184
190
|
*/
|
|
185
|
-
fun isInsetAnimationInProgress(): Boolean
|
|
186
|
-
return insetsAnimationController != null
|
|
187
|
-
}
|
|
191
|
+
fun isInsetAnimationInProgress(): Boolean = insetsAnimationController != null
|
|
188
192
|
|
|
189
193
|
/**
|
|
190
194
|
* Return `true` if an inset animation is currently finishing.
|
|
191
195
|
*/
|
|
192
|
-
fun isInsetAnimationFinishing(): Boolean
|
|
193
|
-
return currentSpringAnimation != null
|
|
194
|
-
}
|
|
196
|
+
fun isInsetAnimationFinishing(): Boolean = currentSpringAnimation != null
|
|
195
197
|
|
|
196
198
|
/**
|
|
197
199
|
* Return `true` if a request to control an inset animation is in progress.
|
|
198
200
|
*/
|
|
199
|
-
fun isInsetAnimationRequestPending(): Boolean
|
|
200
|
-
return pendingRequestCancellationSignal != null
|
|
201
|
-
}
|
|
201
|
+
fun isInsetAnimationRequestPending(): Boolean = pendingRequestCancellationSignal != null
|
|
202
202
|
|
|
203
203
|
/**
|
|
204
204
|
* Cancel the current [WindowInsetsAnimationControllerCompat]. We immediately finish
|
|
@@ -280,10 +280,11 @@ internal class KeyboardAnimationController {
|
|
|
280
280
|
when {
|
|
281
281
|
// If we have a velocity, we can use it's direction to determine
|
|
282
282
|
// the visibility. Upwards == visible
|
|
283
|
-
velocityY != null ->
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
283
|
+
velocityY != null ->
|
|
284
|
+
animateImeToVisibility(
|
|
285
|
+
visible = velocityY < 0,
|
|
286
|
+
velocityY = velocityY,
|
|
287
|
+
)
|
|
287
288
|
// The current inset matches either the shown/hidden inset, finish() immediately
|
|
288
289
|
current == shown -> {
|
|
289
290
|
InteractiveKeyboardProvider.shown = true
|
|
@@ -307,11 +308,12 @@ internal class KeyboardAnimationController {
|
|
|
307
308
|
}
|
|
308
309
|
|
|
309
310
|
fun getCurrentKeyboardHeight(): Int {
|
|
310
|
-
val controller =
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
"
|
|
314
|
-
|
|
311
|
+
val controller =
|
|
312
|
+
insetsAnimationController
|
|
313
|
+
?: throw IllegalStateException(
|
|
314
|
+
"Current WindowInsetsAnimationController is null." +
|
|
315
|
+
"This should only be called if isAnimationInProgress() returns true",
|
|
316
|
+
)
|
|
315
317
|
|
|
316
318
|
return controller.currentInsets.bottom
|
|
317
319
|
}
|
|
@@ -356,37 +358,40 @@ internal class KeyboardAnimationController {
|
|
|
356
358
|
velocityY: Float? = null,
|
|
357
359
|
) {
|
|
358
360
|
@Suppress("detekt:UseCheckOrError")
|
|
359
|
-
val controller =
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
currentSpringAnimation = null
|
|
361
|
+
val controller =
|
|
362
|
+
insetsAnimationController
|
|
363
|
+
?: throw IllegalStateException("Controller should not be null")
|
|
364
|
+
|
|
365
|
+
currentSpringAnimation =
|
|
366
|
+
springAnimationOf(
|
|
367
|
+
setter = {
|
|
368
|
+
insetTo(it.roundToInt())
|
|
369
|
+
},
|
|
370
|
+
getter = { controller.currentInsets.bottom.toFloat() },
|
|
371
|
+
finalPosition =
|
|
372
|
+
when {
|
|
373
|
+
visible -> controller.shownStateInsets.bottom.toFloat()
|
|
374
|
+
else -> controller.hiddenStateInsets.bottom.toFloat()
|
|
375
|
+
},
|
|
376
|
+
).withSpringForceProperties {
|
|
377
|
+
// Tweak the damping value, to remove any bounciness.
|
|
378
|
+
dampingRatio = SpringForce.DAMPING_RATIO_NO_BOUNCY
|
|
379
|
+
// The stiffness value controls the strength of the spring animation, which
|
|
380
|
+
// controls the speed. Medium (the default) is a good value, but feel free to
|
|
381
|
+
// play around with this value.
|
|
382
|
+
stiffness = SpringForce.STIFFNESS_MEDIUM
|
|
383
|
+
}.apply {
|
|
384
|
+
if (velocityY != null) {
|
|
385
|
+
setStartVelocity(velocityY)
|
|
385
386
|
}
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
387
|
+
addEndListener { anim, _, _, _ ->
|
|
388
|
+
if (anim == currentSpringAnimation) {
|
|
389
|
+
currentSpringAnimation = null
|
|
390
|
+
}
|
|
391
|
+
// Once the animation has ended, finish the controller
|
|
392
|
+
finish()
|
|
393
|
+
}
|
|
394
|
+
}.also { it.start() }
|
|
390
395
|
}
|
|
391
396
|
}
|
|
392
397
|
|
|
@@ -11,5 +11,10 @@ interface Interpolator {
|
|
|
11
11
|
* @param offset extra space to the keyboard to activate a gesture
|
|
12
12
|
* @return the distance the keyboard should be moved from its current location.
|
|
13
13
|
*/
|
|
14
|
-
fun interpolate(
|
|
14
|
+
fun interpolate(
|
|
15
|
+
dy: Int,
|
|
16
|
+
absoluteFingerPosition: Int,
|
|
17
|
+
keyboardPosition: Int,
|
|
18
|
+
offset: Int,
|
|
19
|
+
): Int
|
|
15
20
|
}
|
|
@@ -8,8 +8,10 @@ class IosInterpolator : Interpolator {
|
|
|
8
8
|
offset: Int,
|
|
9
9
|
): Int {
|
|
10
10
|
if (
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
// user over scrolled keyboard
|
|
12
|
+
absoluteFingerPosition <= keyboardPosition + offset ||
|
|
13
|
+
// user scrolls up
|
|
14
|
+
dy <= 0
|
|
13
15
|
) {
|
|
14
16
|
return dy
|
|
15
17
|
}
|
package/android/src/main/java/com/reactnativekeyboardcontroller/listeners/FocusedInputObserver.kt
CHANGED
|
@@ -25,16 +25,17 @@ import com.reactnativekeyboardcontroller.extensions.screenLocation
|
|
|
25
25
|
import com.reactnativekeyboardcontroller.traversal.FocusedInputHolder
|
|
26
26
|
import com.reactnativekeyboardcontroller.traversal.ViewHierarchyNavigator
|
|
27
27
|
|
|
28
|
-
val noFocusedInputEvent =
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
28
|
+
val noFocusedInputEvent =
|
|
29
|
+
FocusedInputLayoutChangedEventData(
|
|
30
|
+
x = 0.0,
|
|
31
|
+
y = 0.0,
|
|
32
|
+
width = 0.0,
|
|
33
|
+
height = 0.0,
|
|
34
|
+
absoluteX = 0.0,
|
|
35
|
+
absoluteY = 0.0,
|
|
36
|
+
target = -1,
|
|
37
|
+
parentScrollViewTarget = -1,
|
|
38
|
+
)
|
|
38
39
|
|
|
39
40
|
class FocusedInputObserver(
|
|
40
41
|
val view: View,
|
|
@@ -82,50 +83,52 @@ class FocusedInputObserver(
|
|
|
82
83
|
FocusedInputSelectionChangedEvent(
|
|
83
84
|
surfaceId,
|
|
84
85
|
eventPropagationView.id,
|
|
85
|
-
event =
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
86
|
+
event =
|
|
87
|
+
FocusedInputSelectionChangedEventData(
|
|
88
|
+
target = input.id,
|
|
89
|
+
start = start,
|
|
90
|
+
end = end,
|
|
91
|
+
startX = startX,
|
|
92
|
+
startY = startY,
|
|
93
|
+
endX = endX,
|
|
94
|
+
endY = endY,
|
|
95
|
+
),
|
|
94
96
|
),
|
|
95
97
|
)
|
|
96
98
|
}
|
|
97
|
-
private val focusListener =
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
99
|
+
private val focusListener =
|
|
100
|
+
OnGlobalFocusChangeListener { oldFocus, newFocus ->
|
|
101
|
+
// unfocused or focus was changed
|
|
102
|
+
if (newFocus == null || oldFocus != null) {
|
|
103
|
+
lastFocusedInput?.removeOnLayoutChangeListener(layoutListener)
|
|
104
|
+
lastFocusedInput?.removeTextChangedListener(textWatcher)
|
|
105
|
+
selectionSubscription?.invoke()
|
|
106
|
+
lastFocusedInput = null
|
|
107
|
+
}
|
|
108
|
+
if (newFocus is ReactEditText) {
|
|
109
|
+
lastFocusedInput = newFocus
|
|
110
|
+
newFocus.addOnLayoutChangeListener(layoutListener)
|
|
111
|
+
this.syncUpLayout()
|
|
112
|
+
textWatcher = newFocus.addOnTextChangedListener(textListener)
|
|
113
|
+
selectionSubscription = newFocus.addOnSelectionChangedListener(selectionListener)
|
|
114
|
+
FocusedInputHolder.set(newFocus)
|
|
112
115
|
|
|
113
|
-
|
|
114
|
-
|
|
116
|
+
val allInputFields = ViewHierarchyNavigator.getAllInputFields(context?.rootView)
|
|
117
|
+
val currentIndex = allInputFields.indexOf(newFocus)
|
|
115
118
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
119
|
+
context.emitEvent(
|
|
120
|
+
"KeyboardController::focusDidSet",
|
|
121
|
+
Arguments.createMap().apply {
|
|
122
|
+
putInt("current", currentIndex)
|
|
123
|
+
putInt("count", allInputFields.size)
|
|
124
|
+
},
|
|
125
|
+
)
|
|
126
|
+
}
|
|
127
|
+
// unfocused
|
|
128
|
+
if (newFocus == null) {
|
|
129
|
+
dispatchEventToJS(noFocusedInputEvent)
|
|
130
|
+
}
|
|
123
131
|
}
|
|
124
|
-
// unfocused
|
|
125
|
-
if (newFocus == null) {
|
|
126
|
-
dispatchEventToJS(noFocusedInputEvent)
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
132
|
|
|
130
133
|
init {
|
|
131
134
|
view.viewTreeObserver.addOnGlobalFocusChangeListener(focusListener)
|
|
@@ -135,16 +138,17 @@ class FocusedInputObserver(
|
|
|
135
138
|
val input = lastFocusedInput ?: return
|
|
136
139
|
|
|
137
140
|
val (x, y) = input.screenLocation
|
|
138
|
-
val event =
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
141
|
+
val event =
|
|
142
|
+
FocusedInputLayoutChangedEventData(
|
|
143
|
+
x = input.x.dp,
|
|
144
|
+
y = input.y.dp,
|
|
145
|
+
width = input.width.toFloat().dp,
|
|
146
|
+
height = input.height.toFloat().dp,
|
|
147
|
+
absoluteX = x.toFloat().dp,
|
|
148
|
+
absoluteY = y.toFloat().dp,
|
|
149
|
+
target = input.id,
|
|
150
|
+
parentScrollViewTarget = input.parentScrollViewTarget,
|
|
151
|
+
)
|
|
148
152
|
|
|
149
153
|
dispatchEventToJS(event)
|
|
150
154
|
}
|
|
@@ -38,7 +38,8 @@ class KeyboardAnimationCallback(
|
|
|
38
38
|
val view: View,
|
|
39
39
|
val context: ThemedReactContext?,
|
|
40
40
|
private val config: KeyboardAnimationCallbackConfig,
|
|
41
|
-
) : WindowInsetsAnimationCompat.Callback(config.dispatchMode),
|
|
41
|
+
) : WindowInsetsAnimationCompat.Callback(config.dispatchMode),
|
|
42
|
+
OnApplyWindowInsetsListener {
|
|
42
43
|
private val surfaceId = UIManagerHelper.getSurfaceId(eventPropagationView)
|
|
43
44
|
|
|
44
45
|
// state variables
|
|
@@ -51,46 +52,47 @@ class KeyboardAnimationCallback(
|
|
|
51
52
|
private var animationsToSkip = hashSetOf<WindowInsetsAnimationCompat>()
|
|
52
53
|
|
|
53
54
|
// listeners
|
|
54
|
-
private val focusListener =
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
KeyboardTransitionEvent(
|
|
68
|
-
surfaceId,
|
|
55
|
+
private val focusListener =
|
|
56
|
+
OnGlobalFocusChangeListener { oldFocus, newFocus ->
|
|
57
|
+
if (newFocus is ReactEditText) {
|
|
58
|
+
viewTagFocused = newFocus.id
|
|
59
|
+
|
|
60
|
+
// keyboard is visible and focus has been changed
|
|
61
|
+
if (this.isKeyboardVisible && oldFocus !== null) {
|
|
62
|
+
// imitate iOS behavior and send two instant start/end events containing an info about new tag
|
|
63
|
+
// 1. onStart/onMove/onEnd can be still dispatched after, if keyboard change size (numeric -> alphabetic type)
|
|
64
|
+
// 2. event should be send only when keyboard is visible, since this event arrives earlier -> `tag` will be
|
|
65
|
+
// 100% included in onStart/onMove/onEnd life cycles, but triggering onStart/onEnd several time
|
|
66
|
+
// can bring breaking changes
|
|
67
|
+
context.dispatchEvent(
|
|
69
68
|
eventPropagationView.id,
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
69
|
+
KeyboardTransitionEvent(
|
|
70
|
+
surfaceId,
|
|
71
|
+
eventPropagationView.id,
|
|
72
|
+
"topKeyboardMoveStart",
|
|
73
|
+
this.persistentKeyboardHeight,
|
|
74
|
+
1.0,
|
|
75
|
+
0,
|
|
76
|
+
viewTagFocused,
|
|
77
|
+
),
|
|
78
|
+
)
|
|
79
|
+
context.dispatchEvent(
|
|
81
80
|
eventPropagationView.id,
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
81
|
+
KeyboardTransitionEvent(
|
|
82
|
+
surfaceId,
|
|
83
|
+
eventPropagationView.id,
|
|
84
|
+
"topKeyboardMoveEnd",
|
|
85
|
+
this.persistentKeyboardHeight,
|
|
86
|
+
1.0,
|
|
87
|
+
0,
|
|
88
|
+
viewTagFocused,
|
|
89
|
+
),
|
|
90
|
+
)
|
|
91
|
+
context.emitEvent("KeyboardController::keyboardWillShow", getEventParams(this.persistentKeyboardHeight))
|
|
92
|
+
context.emitEvent("KeyboardController::keyboardDidShow", getEventParams(this.persistentKeyboardHeight))
|
|
93
|
+
}
|
|
91
94
|
}
|
|
92
95
|
}
|
|
93
|
-
}
|
|
94
96
|
private var layoutObserver: FocusedInputObserver? = null
|
|
95
97
|
|
|
96
98
|
init {
|
|
@@ -113,7 +115,10 @@ class KeyboardAnimationCallback(
|
|
|
113
115
|
* have to implement `onApplyWindowInsets` listener and simulate onStart/onProgress/onEnd
|
|
114
116
|
* events when keyboard changes its size.
|
|
115
117
|
*/
|
|
116
|
-
override fun onApplyWindowInsets(
|
|
118
|
+
override fun onApplyWindowInsets(
|
|
119
|
+
v: View,
|
|
120
|
+
insets: WindowInsetsCompat,
|
|
121
|
+
): WindowInsetsCompat {
|
|
117
122
|
val keyboardHeight = getCurrentKeyboardHeight()
|
|
118
123
|
// when keyboard appears values will be (false && true)
|
|
119
124
|
// when keyboard disappears values will be (true && false)
|
|
@@ -218,9 +223,10 @@ class KeyboardAnimationCallback(
|
|
|
218
223
|
if (config.hasTranslucentNavigationBar) {
|
|
219
224
|
otherInset = Insets.NONE
|
|
220
225
|
}
|
|
221
|
-
val diff =
|
|
222
|
-
Insets.
|
|
223
|
-
|
|
226
|
+
val diff =
|
|
227
|
+
Insets.subtract(typesInset, otherInset).let {
|
|
228
|
+
Insets.max(it, Insets.NONE)
|
|
229
|
+
}
|
|
224
230
|
val diffY = (diff.bottom - diff.top).toFloat()
|
|
225
231
|
val height = diffY.dp
|
|
226
232
|
|
package/android/src/main/java/com/reactnativekeyboardcontroller/listeners/WindowDimensionListener.kt
CHANGED
|
@@ -8,9 +8,14 @@ import com.reactnativekeyboardcontroller.extensions.content
|
|
|
8
8
|
import com.reactnativekeyboardcontroller.extensions.dp
|
|
9
9
|
import com.reactnativekeyboardcontroller.extensions.emitEvent
|
|
10
10
|
|
|
11
|
-
data class Dimensions(
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
data class Dimensions(
|
|
12
|
+
val width: Double,
|
|
13
|
+
val height: Double,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
class WindowDimensionListener(
|
|
17
|
+
private val context: ThemedReactContext?,
|
|
18
|
+
) {
|
|
14
19
|
private var lastDispatchedDimensions = Dimensions(0.0, 0.0)
|
|
15
20
|
|
|
16
21
|
init {
|
|
@@ -33,10 +38,11 @@ class WindowDimensionListener(private val context: ThemedReactContext?) {
|
|
|
33
38
|
return
|
|
34
39
|
}
|
|
35
40
|
|
|
36
|
-
val newDimensions =
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
41
|
+
val newDimensions =
|
|
42
|
+
Dimensions(
|
|
43
|
+
content.width.toFloat().dp,
|
|
44
|
+
content.height.toFloat().dp + content.marginTop.toFloat().dp,
|
|
45
|
+
)
|
|
40
46
|
|
|
41
47
|
if (newDimensions != lastDispatchedDimensions) {
|
|
42
48
|
lastDispatchedDimensions = newDimensions
|
|
@@ -6,13 +6,21 @@ import com.reactnativekeyboardcontroller.BuildConfig
|
|
|
6
6
|
object Logger {
|
|
7
7
|
private val enabled = BuildConfig.DEBUG
|
|
8
8
|
|
|
9
|
-
fun i(
|
|
9
|
+
fun i(
|
|
10
|
+
tag: String?,
|
|
11
|
+
message: String,
|
|
12
|
+
throwable: Throwable? = null,
|
|
13
|
+
) {
|
|
10
14
|
if (enabled) {
|
|
11
15
|
Log.i(tag, message, throwable)
|
|
12
16
|
}
|
|
13
17
|
}
|
|
14
18
|
|
|
15
|
-
fun w(
|
|
19
|
+
fun w(
|
|
20
|
+
tag: String?,
|
|
21
|
+
message: String,
|
|
22
|
+
throwable: Throwable? = null,
|
|
23
|
+
) {
|
|
16
24
|
if (enabled) {
|
|
17
25
|
Log.w(tag, message, throwable)
|
|
18
26
|
}
|