react-native-keyboard-controller 1.13.3 → 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 +82 -62
- package/android/src/main/java/com/reactnativekeyboardcontroller/extensions/ReactContext.kt +9 -4
- package/android/src/main/java/com/reactnativekeyboardcontroller/extensions/ThemedReactContext.kt +12 -5
- package/android/src/main/java/com/reactnativekeyboardcontroller/extensions/View.kt +12 -10
- 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 +52 -46
- package/android/src/main/java/com/reactnativekeyboardcontroller/listeners/WindowDimensionListener.kt +13 -7
- package/android/src/main/java/com/reactnativekeyboardcontroller/log/Logger.kt +28 -0
- 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 +15 -13
- package/android/src/main/java/com/reactnativekeyboardcontroller/modules/KeyboardControllerModuleImpl.kt +8 -8
- package/android/src/main/java/com/reactnativekeyboardcontroller/modules/StatusBarManagerCompatModuleImpl.kt +10 -5
- 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 +24 -19
- 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/hooks/index.js +2 -4
- package/lib/commonjs/hooks/index.js.map +1 -1
- package/lib/commonjs/index.js +9 -1
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/internal.js +24 -12
- package/lib/commonjs/internal.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/hooks/index.js +3 -4
- package/lib/module/hooks/index.js.map +1 -1
- package/lib/module/index.js +1 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/internal.js +24 -12
- package/lib/module/internal.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/hooks/index.ts +3 -5
- package/src/index.ts +1 -0
- package/src/internal.ts +34 -15
- 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
- package/lib/commonjs/hooks/useSyncEffect/index.js +0 -37
- package/lib/commonjs/hooks/useSyncEffect/index.js.map +0 -1
- package/lib/module/hooks/useSyncEffect/index.js +0 -31
- package/lib/module/hooks/useSyncEffect/index.js.map +0 -1
- package/lib/typescript/hooks/useSyncEffect/index.d.ts +0 -14
- package/src/hooks/useSyncEffect/index.ts +0 -36
|
@@ -5,9 +5,14 @@ import android.view.ViewGroup
|
|
|
5
5
|
import com.facebook.react.bridge.ReactContext
|
|
6
6
|
|
|
7
7
|
val ReactContext.rootView: View?
|
|
8
|
-
get() =
|
|
8
|
+
get() =
|
|
9
|
+
this.currentActivity
|
|
10
|
+
?.window
|
|
11
|
+
?.decorView
|
|
12
|
+
?.rootView
|
|
9
13
|
|
|
10
14
|
val ReactContext.content: ViewGroup?
|
|
11
|
-
get() =
|
|
12
|
-
|
|
13
|
-
|
|
15
|
+
get() =
|
|
16
|
+
this.currentActivity?.window?.decorView?.rootView?.findViewById(
|
|
17
|
+
androidx.appcompat.R.id.action_bar_root,
|
|
18
|
+
)
|
package/android/src/main/java/com/reactnativekeyboardcontroller/extensions/ThemedReactContext.kt
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
package com.reactnativekeyboardcontroller.extensions
|
|
2
2
|
|
|
3
|
-
import android.util.Log
|
|
4
3
|
import com.facebook.react.bridge.ReactContext
|
|
5
4
|
import com.facebook.react.bridge.WritableMap
|
|
6
5
|
import com.facebook.react.modules.core.DeviceEventManagerModule
|
|
@@ -9,21 +8,29 @@ import com.facebook.react.uimanager.UIManagerHelper
|
|
|
9
8
|
import com.facebook.react.uimanager.events.Event
|
|
10
9
|
import com.facebook.react.uimanager.events.EventDispatcher
|
|
11
10
|
import com.reactnativekeyboardcontroller.listeners.WindowDimensionListener
|
|
11
|
+
import com.reactnativekeyboardcontroller.log.Logger
|
|
12
12
|
|
|
13
13
|
fun ThemedReactContext.setupWindowDimensionsListener() {
|
|
14
14
|
WindowDimensionListener(this)
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
fun ThemedReactContext?.dispatchEvent(
|
|
17
|
+
fun ThemedReactContext?.dispatchEvent(
|
|
18
|
+
viewId: Int,
|
|
19
|
+
event: Event<*>,
|
|
20
|
+
) {
|
|
18
21
|
val eventDispatcher: EventDispatcher? =
|
|
19
22
|
UIManagerHelper.getEventDispatcherForReactTag(this as ReactContext, viewId)
|
|
20
23
|
eventDispatcher?.dispatchEvent(event)
|
|
21
24
|
}
|
|
22
25
|
|
|
23
|
-
fun ThemedReactContext?.emitEvent(
|
|
24
|
-
|
|
26
|
+
fun ThemedReactContext?.emitEvent(
|
|
27
|
+
event: String,
|
|
28
|
+
params: WritableMap,
|
|
29
|
+
) {
|
|
30
|
+
this
|
|
31
|
+
?.reactApplicationContext
|
|
25
32
|
?.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
|
|
26
33
|
?.emit(event, params)
|
|
27
34
|
|
|
28
|
-
|
|
35
|
+
Logger.i("ThemedReactContext", event)
|
|
29
36
|
}
|
|
@@ -2,9 +2,9 @@ package com.reactnativekeyboardcontroller.extensions
|
|
|
2
2
|
|
|
3
3
|
import android.graphics.Rect
|
|
4
4
|
import android.os.Build
|
|
5
|
-
import android.util.Log
|
|
6
5
|
import android.view.View
|
|
7
6
|
import androidx.annotation.RequiresApi
|
|
7
|
+
import com.reactnativekeyboardcontroller.log.Logger
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Call this every time when using [ViewCompat.setOnApplyWindowInsetsListener]
|
|
@@ -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
|
|
|
@@ -43,7 +45,7 @@ fun View.copyBoundsInWindow(rect: Rect) {
|
|
|
43
45
|
getLocationInWindow(tmpIntArr)
|
|
44
46
|
rect.offset(tmpIntArr[0], tmpIntArr[1])
|
|
45
47
|
} else {
|
|
46
|
-
|
|
48
|
+
Logger.w("View.copyBoundsInWindow", "Can not copy bounds as view is not attached to window")
|
|
47
49
|
}
|
|
48
50
|
}
|
|
49
51
|
|
|
@@ -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
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
package com.reactnativekeyboardcontroller.listeners
|
|
2
2
|
|
|
3
3
|
import android.os.Build
|
|
4
|
-
import android.util.Log
|
|
5
4
|
import android.view.View
|
|
6
5
|
import android.view.ViewTreeObserver.OnGlobalFocusChangeListener
|
|
7
6
|
import androidx.core.graphics.Insets
|
|
@@ -21,6 +20,7 @@ import com.reactnativekeyboardcontroller.extensions.dp
|
|
|
21
20
|
import com.reactnativekeyboardcontroller.extensions.emitEvent
|
|
22
21
|
import com.reactnativekeyboardcontroller.extensions.isKeyboardAnimation
|
|
23
22
|
import com.reactnativekeyboardcontroller.interactive.InteractiveKeyboardProvider
|
|
23
|
+
import com.reactnativekeyboardcontroller.log.Logger
|
|
24
24
|
import kotlin.math.abs
|
|
25
25
|
|
|
26
26
|
private val TAG = KeyboardAnimationCallback::class.qualifiedName
|
|
@@ -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)
|
|
@@ -137,7 +142,7 @@ class KeyboardAnimationCallback(
|
|
|
137
142
|
val isKeyboardSizeEqual = this.persistentKeyboardHeight == keyboardHeight
|
|
138
143
|
|
|
139
144
|
if (isKeyboardFullyVisible && !isKeyboardSizeEqual && !isResizeHandledInCallbackMethods) {
|
|
140
|
-
|
|
145
|
+
Logger.i(TAG, "onApplyWindowInsets: ${this.persistentKeyboardHeight} -> $keyboardHeight")
|
|
141
146
|
layoutObserver?.syncUpLayout()
|
|
142
147
|
this.onKeyboardResized(keyboardHeight)
|
|
143
148
|
}
|
|
@@ -182,7 +187,7 @@ class KeyboardAnimationCallback(
|
|
|
182
187
|
getEventParams(keyboardHeight),
|
|
183
188
|
)
|
|
184
189
|
|
|
185
|
-
|
|
190
|
+
Logger.i(TAG, "HEIGHT:: $keyboardHeight TAG:: $viewTagFocused")
|
|
186
191
|
context.dispatchEvent(
|
|
187
192
|
eventPropagationView.id,
|
|
188
193
|
KeyboardTransitionEvent(
|
|
@@ -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
|
|
|
@@ -229,9 +235,9 @@ class KeyboardAnimationCallback(
|
|
|
229
235
|
progress = abs((height / persistentKeyboardHeight)).let { if (it.isNaN()) 0.0 else it }
|
|
230
236
|
} catch (e: ArithmeticException) {
|
|
231
237
|
// do nothing, just log an exception send progress as 0
|
|
232
|
-
|
|
238
|
+
Logger.w(TAG, "Caught arithmetic exception during `progress` calculation: $e")
|
|
233
239
|
}
|
|
234
|
-
|
|
240
|
+
Logger.i(
|
|
235
241
|
TAG,
|
|
236
242
|
"DiffY: $diffY $height $progress ${InteractiveKeyboardProvider.isInteractive} $viewTagFocused",
|
|
237
243
|
)
|