react-native-keyboard-controller 1.0.0-alpha.3 → 1.0.1
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 +5 -56
- package/android/build.gradle +1 -1
- package/android/gradle.properties +2 -0
- package/android/src/main/java/com/reactnativekeyboardcontroller/EdgeToEdgeReactViewGroup.kt +2 -0
- package/android/src/main/java/com/reactnativekeyboardcontroller/KeyboardControllerPackage.kt +6 -6
- package/android/src/main/java/com/reactnativekeyboardcontroller/KeyboardControllerViewManager.kt +15 -2
- package/android/src/main/java/com/reactnativekeyboardcontroller/StatusBarManagerCompatModule.kt +95 -0
- package/android/src/main/java/com/reactnativekeyboardcontroller/TranslateDeferringInsetsAnimationCallback.kt +49 -43
- package/ios/.swift-version +1 -0
- package/ios/.swiftformat +5 -0
- package/ios/.swiftlint.yml +5 -0
- package/ios/KeyboardControllerModule.swift +17 -17
- package/ios/KeyboardControllerViewManager.swift +87 -59
- package/ios/KeyboardMoveEvent.swift +31 -27
- package/lib/commonjs/animated.js +14 -11
- package/lib/commonjs/animated.js.map +1 -1
- package/lib/commonjs/index.js +2 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/monkey-patch.js +44 -0
- package/lib/commonjs/monkey-patch.js.map +1 -0
- package/lib/module/animated.js +13 -12
- package/lib/module/animated.js.map +1 -1
- package/lib/module/index.js +1 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/monkey-patch.js +36 -0
- package/lib/module/monkey-patch.js.map +1 -0
- package/lib/typescript/animated.d.ts +5 -0
- package/lib/typescript/index.d.ts +1 -0
- package/lib/typescript/monkey-patch.d.ts +1 -0
- package/package.json +9 -6
- package/src/animated.tsx +20 -16
- package/src/index.ts +2 -0
- package/src/monkey-patch.tsx +36 -0
- package/android/.gradle/6.8/executionHistory/executionHistory.lock +0 -0
- package/android/.gradle/6.8/fileChanges/last-build.bin +0 -0
- package/android/.gradle/6.8/fileHashes/fileHashes.lock +0 -0
- package/android/.gradle/6.8/gc.properties +0 -0
- package/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
- package/android/.gradle/buildOutputCleanup/cache.properties +0 -2
- package/android/.gradle/checksums/checksums.lock +0 -0
- package/android/.gradle/configuration-cache/gc.properties +0 -0
- package/android/.gradle/vcs-1/gc.properties +0 -0
- package/ios/KeyboardController.xcodeproj/project.xcworkspace/contents.xcworkspacedata +0 -7
- package/ios/KeyboardController.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +0 -8
- package/ios/KeyboardController.xcodeproj/project.xcworkspace/xcuserdata/kiryl.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
- package/ios/KeyboardController.xcodeproj/xcuserdata/kiryl.xcuserdatad/xcschemes/xcschememanagement.plist +0 -14
package/README.md
CHANGED
|
@@ -2,14 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
Keyboard manager which works in identical way on both iOS and Android.
|
|
4
4
|
|
|
5
|
-
> **Note**: This library is still in development and in `alpha` stage. So most likely it has bugs/issues - don't hesitate to report if you find them 🙂.
|
|
6
|
-
|
|
7
5
|
## Demonstration
|
|
8
6
|
|
|
9
|
-
<
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
</div>
|
|
7
|
+
<img src="./gifs/demo.gif?raw=true" width="60%">
|
|
8
|
+
|
|
9
|
+
## Key features
|
|
13
10
|
|
|
14
11
|
- mapping keyboard appearance to animated values 😎
|
|
15
12
|
- missing `keyboardWillShow` / `keyboardWillHide` events are available on Android 😍
|
|
@@ -18,8 +15,6 @@ Keyboard manager which works in identical way on both iOS and Android.
|
|
|
18
15
|
- interactive keyboard dismissing (planned) 👆📱
|
|
19
16
|
- and more is coming... Stay tuned! 😊
|
|
20
17
|
|
|
21
|
-
<br clear="right" />
|
|
22
|
-
|
|
23
18
|
## Installation
|
|
24
19
|
|
|
25
20
|
Install `react-native-keyboard-controller` package from npm:
|
|
@@ -30,55 +25,9 @@ yarn add react-native-keyboard-controller
|
|
|
30
25
|
# npm install react-native-keyboard-controller --save
|
|
31
26
|
```
|
|
32
27
|
|
|
33
|
-
##
|
|
34
|
-
|
|
35
|
-
For more comprehensive usage you can have a look on [example](https://github.com/kirillzyusko/react-native-keyboard-controller/tree/main/example).
|
|
36
|
-
|
|
37
|
-
Below you can see a short overview of library API:
|
|
28
|
+
## Documentation
|
|
38
29
|
|
|
39
|
-
|
|
40
|
-
import {
|
|
41
|
-
KeyboardProvider,
|
|
42
|
-
useKeyboardAnimation,
|
|
43
|
-
} from 'react-native-keyboard-controller';
|
|
44
|
-
|
|
45
|
-
// 1. wrap your app in Provider
|
|
46
|
-
<KeyboardProvider>
|
|
47
|
-
<AppContainer />
|
|
48
|
-
</KeyboardProvider>
|
|
49
|
-
|
|
50
|
-
// 2. get animation values where you need them
|
|
51
|
-
const { height, progress } = useKeyboardAnimation();
|
|
52
|
-
|
|
53
|
-
// 3. Animate any elements as you wish :)
|
|
54
|
-
<Animated.View
|
|
55
|
-
style={{
|
|
56
|
-
width: 50,
|
|
57
|
-
height: 50,
|
|
58
|
-
backgroundColor: 'red',
|
|
59
|
-
borderRadius: 25,
|
|
60
|
-
// the element will move up with the keyboard
|
|
61
|
-
transform: [{ translateY: height }],
|
|
62
|
-
}}
|
|
63
|
-
/>
|
|
64
|
-
<Animated.View
|
|
65
|
-
style={{
|
|
66
|
-
width: 50,
|
|
67
|
-
height: 50,
|
|
68
|
-
backgroundColor: 'green',
|
|
69
|
-
borderRadius: 25,
|
|
70
|
-
transform: [
|
|
71
|
-
{
|
|
72
|
-
// or use custom interpolation using `progress`
|
|
73
|
-
translateX: progress.interpolate({
|
|
74
|
-
inputRange: [0, 1],
|
|
75
|
-
outputRange: [0, 100],
|
|
76
|
-
}),
|
|
77
|
-
},
|
|
78
|
-
],
|
|
79
|
-
}}
|
|
80
|
-
/>
|
|
81
|
-
```
|
|
30
|
+
Check out our dedicated documentation page for info about this library, API reference and more: [https://kirillzyusko.github.io/react-native-keyboard-controller/](https://kirillzyusko.github.io/react-native-keyboard-controller/)
|
|
82
31
|
|
|
83
32
|
## Contributing
|
|
84
33
|
|
package/android/build.gradle
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
package com.reactnativekeyboardcontroller
|
|
2
2
|
|
|
3
|
+
import android.annotation.SuppressLint
|
|
3
4
|
import androidx.core.view.WindowCompat
|
|
4
5
|
import com.facebook.react.uimanager.ThemedReactContext
|
|
5
6
|
import com.facebook.react.views.view.ReactViewGroup
|
|
6
7
|
|
|
8
|
+
@SuppressLint("ViewConstructor")
|
|
7
9
|
class EdgeToEdgeReactViewGroup(private val reactContext: ThemedReactContext) : ReactViewGroup(reactContext) {
|
|
8
10
|
override fun onAttachedToWindow() {
|
|
9
11
|
super.onAttachedToWindow()
|
package/android/src/main/java/com/reactnativekeyboardcontroller/KeyboardControllerPackage.kt
CHANGED
|
@@ -6,11 +6,11 @@ import com.facebook.react.bridge.ReactApplicationContext
|
|
|
6
6
|
import com.facebook.react.uimanager.ViewManager
|
|
7
7
|
|
|
8
8
|
class KeyboardControllerPackage : ReactPackage {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> {
|
|
10
|
+
return listOf(KeyboardControllerModule(reactContext), StatusBarManagerCompatModule(reactContext))
|
|
11
|
+
}
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
|
|
14
|
+
return listOf(KeyboardControllerViewManager(reactContext))
|
|
15
|
+
}
|
|
16
16
|
}
|
package/android/src/main/java/com/reactnativekeyboardcontroller/KeyboardControllerViewManager.kt
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
package com.reactnativekeyboardcontroller
|
|
2
2
|
|
|
3
|
+
import android.util.Log
|
|
3
4
|
import androidx.appcompat.widget.FitWindowsLinearLayout
|
|
4
|
-
import androidx.core.view
|
|
5
|
+
import androidx.core.view.ViewCompat
|
|
6
|
+
import androidx.core.view.WindowInsetsAnimationCompat
|
|
7
|
+
import androidx.core.view.WindowInsetsCompat
|
|
5
8
|
import com.facebook.react.bridge.ReactApplicationContext
|
|
6
9
|
import com.facebook.react.common.MapBuilder
|
|
7
10
|
import com.facebook.react.uimanager.ThemedReactContext
|
|
@@ -11,6 +14,7 @@ import com.facebook.react.views.view.ReactViewManager
|
|
|
11
14
|
import com.reactnativekeyboardcontroller.events.KeyboardTransitionEvent
|
|
12
15
|
|
|
13
16
|
class KeyboardControllerViewManager(reactContext: ReactApplicationContext) : ReactViewManager() {
|
|
17
|
+
private val TAG = KeyboardControllerViewManager::class.qualifiedName
|
|
14
18
|
private var mReactContext = reactContext
|
|
15
19
|
private var isStatusBarTranslucent = false
|
|
16
20
|
|
|
@@ -18,6 +22,15 @@ class KeyboardControllerViewManager(reactContext: ReactApplicationContext) : Rea
|
|
|
18
22
|
|
|
19
23
|
override fun createViewInstance(reactContext: ThemedReactContext): ReactViewGroup {
|
|
20
24
|
val view = EdgeToEdgeReactViewGroup(reactContext)
|
|
25
|
+
val activity = mReactContext.currentActivity
|
|
26
|
+
|
|
27
|
+
if (activity == null) {
|
|
28
|
+
Log.w(TAG, "Can not setup keyboard animation listener, since `currentActivity` is null")
|
|
29
|
+
return view
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
val window = activity.window
|
|
33
|
+
val decorView = window.decorView
|
|
21
34
|
|
|
22
35
|
ViewCompat.setOnApplyWindowInsetsListener(view) { v, insets ->
|
|
23
36
|
val content =
|
|
@@ -33,7 +46,7 @@ class KeyboardControllerViewManager(reactContext: ReactApplicationContext) : Rea
|
|
|
33
46
|
}
|
|
34
47
|
|
|
35
48
|
ViewCompat.setWindowInsetsAnimationCallback(
|
|
36
|
-
|
|
49
|
+
decorView,
|
|
37
50
|
TranslateDeferringInsetsAnimationCallback(
|
|
38
51
|
view = view,
|
|
39
52
|
persistentInsetTypes = WindowInsetsCompat.Type.systemBars(),
|
package/android/src/main/java/com/reactnativekeyboardcontroller/StatusBarManagerCompatModule.kt
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
package com.reactnativekeyboardcontroller
|
|
2
|
+
|
|
3
|
+
import android.animation.ArgbEvaluator
|
|
4
|
+
import android.animation.ValueAnimator
|
|
5
|
+
import android.os.Build
|
|
6
|
+
import android.util.Log
|
|
7
|
+
import androidx.annotation.RequiresApi
|
|
8
|
+
import androidx.core.view.WindowInsetsCompat
|
|
9
|
+
import androidx.core.view.WindowInsetsControllerCompat
|
|
10
|
+
import com.facebook.react.bridge.ReactApplicationContext
|
|
11
|
+
import com.facebook.react.bridge.ReactContextBaseJavaModule
|
|
12
|
+
import com.facebook.react.bridge.ReactMethod
|
|
13
|
+
import com.facebook.react.bridge.UiThreadUtil
|
|
14
|
+
|
|
15
|
+
class StatusBarManagerCompatModule(private val mReactContext: ReactApplicationContext) : ReactContextBaseJavaModule(mReactContext) {
|
|
16
|
+
private val TAG = StatusBarManagerCompatModule::class.qualifiedName
|
|
17
|
+
private var controller: WindowInsetsControllerCompat? = null
|
|
18
|
+
|
|
19
|
+
override fun getName(): String = "StatusBarManagerCompat"
|
|
20
|
+
|
|
21
|
+
@ReactMethod
|
|
22
|
+
private fun setHidden(hidden: Boolean) {
|
|
23
|
+
UiThreadUtil.runOnUiThread {
|
|
24
|
+
if (hidden) {
|
|
25
|
+
getController()?.hide(WindowInsetsCompat.Type.statusBars())
|
|
26
|
+
} else {
|
|
27
|
+
getController()?.show(WindowInsetsCompat.Type.statusBars())
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
|
|
33
|
+
@ReactMethod
|
|
34
|
+
private fun setColor(color: Int, animated: Boolean) {
|
|
35
|
+
val activity = mReactContext.currentActivity
|
|
36
|
+
if (activity == null) {
|
|
37
|
+
Log.w(TAG, "StatusBarManagerCompatModule: Ignored status bar change, current activity is null.")
|
|
38
|
+
return
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
UiThreadUtil.runOnUiThread {
|
|
42
|
+
val window = activity.window
|
|
43
|
+
|
|
44
|
+
if (animated) {
|
|
45
|
+
val curColor: Int = window.statusBarColor
|
|
46
|
+
val colorAnimation = ValueAnimator.ofObject(ArgbEvaluator(), curColor, color)
|
|
47
|
+
colorAnimation.addUpdateListener { animator ->
|
|
48
|
+
window.statusBarColor = animator.animatedValue as Int
|
|
49
|
+
}
|
|
50
|
+
colorAnimation.setDuration(300).startDelay = 0
|
|
51
|
+
colorAnimation.start()
|
|
52
|
+
} else {
|
|
53
|
+
window.statusBarColor = color
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
@ReactMethod
|
|
59
|
+
private fun setTranslucent(translucent: Boolean) {
|
|
60
|
+
// the status bar is translucent by default (once you wrapped App in Provider,
|
|
61
|
+
// and EdgeToEdgeReactViewGroup has been mounted and called
|
|
62
|
+
// `setDecorFitsSystemWindows(window, false)`. By default this library applies default padding
|
|
63
|
+
// which equal to StatusBar height, so it will have a default RN app behavior. Though once you
|
|
64
|
+
// need to set StatusBar as translucent, you will need to use `statusBarTranslucent` prop on
|
|
65
|
+
// `KeyboardProvider` (it will preventing of applying additional padding, and status bar will be
|
|
66
|
+
// translucent. Though it's important to note, that this value is not reactive (i. e. if you change
|
|
67
|
+
// `statusBarTranslucent` in runtime it will not have any effect. Just theoretically I could make
|
|
68
|
+
// it reactive, but I know, that most of apps or don't use StatusBar translucency at all or they are
|
|
69
|
+
// specifying it for entire app, so I don't see a lot of sense to make it reactive as of now. If your
|
|
70
|
+
// app requires to dynamically manage it - just shoot an issue and I will try to add a support fot that.
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
@ReactMethod
|
|
74
|
+
private fun setStyle(style: String) {
|
|
75
|
+
UiThreadUtil.runOnUiThread {
|
|
76
|
+
getController()?.isAppearanceLightStatusBars = style == "dark-content"
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
private fun getController(): WindowInsetsControllerCompat? {
|
|
81
|
+
if (this.controller == null) {
|
|
82
|
+
val activity = mReactContext.currentActivity
|
|
83
|
+
if (activity == null) {
|
|
84
|
+
Log.w(TAG, "StatusBarManagerCompatModule: can not get `WindowInsetsControllerCompat` because current activity is null.")
|
|
85
|
+
return this.controller
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
val window = activity.window
|
|
89
|
+
|
|
90
|
+
this.controller = WindowInsetsControllerCompat(window, window.decorView)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return this.controller
|
|
94
|
+
}
|
|
95
|
+
}
|
|
@@ -31,7 +31,13 @@ import com.facebook.react.views.view.ReactViewGroup
|
|
|
31
31
|
import com.reactnativekeyboardcontroller.events.KeyboardTransitionEvent
|
|
32
32
|
import java.util.*
|
|
33
33
|
|
|
34
|
-
fun toDp(px: Float, context: Context): Int
|
|
34
|
+
fun toDp(px: Float, context: Context?): Int {
|
|
35
|
+
if (context == null) {
|
|
36
|
+
return 0
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return (px / context.resources.displayMetrics.density).toInt()
|
|
40
|
+
}
|
|
35
41
|
|
|
36
42
|
/**
|
|
37
43
|
* A [WindowInsetsAnimationCompat.Callback] which will translate/move the given view during any
|
|
@@ -61,10 +67,10 @@ class TranslateDeferringInsetsAnimationCallback(
|
|
|
61
67
|
private var persistentKeyboardHeight = 0
|
|
62
68
|
|
|
63
69
|
init {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
70
|
+
require(persistentInsetTypes and deferredInsetTypes == 0) {
|
|
71
|
+
"persistentInsetTypes and deferredInsetTypes can not contain any of " +
|
|
72
|
+
" same WindowInsetsCompat.Type values"
|
|
73
|
+
}
|
|
68
74
|
}
|
|
69
75
|
|
|
70
76
|
override fun onStart(
|
|
@@ -81,9 +87,9 @@ class TranslateDeferringInsetsAnimationCallback(
|
|
|
81
87
|
|
|
82
88
|
val params: WritableMap = Arguments.createMap()
|
|
83
89
|
params.putInt("height", keyboardHeight)
|
|
84
|
-
context?.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)?.emit("KeyboardController::" + if(!isKeyboardVisible) "keyboardWillHide" else "keyboardWillShow", params)
|
|
90
|
+
context?.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)?.emit("KeyboardController::" + if (!isKeyboardVisible) "keyboardWillHide" else "keyboardWillShow", params)
|
|
85
91
|
|
|
86
|
-
Log.i(TAG, "KeyboardController::" + if(!isKeyboardVisible) "keyboardWillHide" else "keyboardWillShow")
|
|
92
|
+
Log.i(TAG, "KeyboardController::" + if (!isKeyboardVisible) "keyboardWillHide" else "keyboardWillShow")
|
|
87
93
|
Log.i(TAG, "HEIGHT:: $keyboardHeight")
|
|
88
94
|
|
|
89
95
|
return super.onStart(animation, bounds)
|
|
@@ -95,9 +101,9 @@ class TranslateDeferringInsetsAnimationCallback(
|
|
|
95
101
|
val isKeyboardVisible = isKeyboardVisible()
|
|
96
102
|
|
|
97
103
|
val params: WritableMap = Arguments.createMap()
|
|
98
|
-
context?.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)?.emit("KeyboardController::" + if(!isKeyboardVisible) "keyboardDidHide" else "keyboardDidShow", params)
|
|
104
|
+
context?.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)?.emit("KeyboardController::" + if (!isKeyboardVisible) "keyboardDidHide" else "keyboardDidShow", params)
|
|
99
105
|
|
|
100
|
-
Log.i(TAG, "KeyboardController::" + if(!isKeyboardVisible) "keyboardDidHide" else "keyboardDidShow")
|
|
106
|
+
Log.i(TAG, "KeyboardController::" + if (!isKeyboardVisible) "keyboardDidHide" else "keyboardDidShow")
|
|
101
107
|
}
|
|
102
108
|
|
|
103
109
|
private fun isKeyboardVisible(): Boolean {
|
|
@@ -112,41 +118,41 @@ class TranslateDeferringInsetsAnimationCallback(
|
|
|
112
118
|
val navigationBar = insets?.getInsets(WindowInsetsCompat.Type.navigationBars())?.bottom ?: 0
|
|
113
119
|
|
|
114
120
|
// on hide it will be negative value, so we are using max function
|
|
115
|
-
return Math.max(toDp((keyboardHeight - navigationBar).toFloat(), context
|
|
121
|
+
return Math.max(toDp((keyboardHeight - navigationBar).toFloat(), context), 0)
|
|
116
122
|
}
|
|
117
123
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
}
|
|
134
|
-
val diffY = (diff.top - diff.bottom).toFloat()
|
|
135
|
-
val height = toDp(diffY, context!!)
|
|
136
|
-
|
|
137
|
-
var progress = 0.0
|
|
138
|
-
try {
|
|
139
|
-
progress = Math.abs((height.toDouble() / persistentKeyboardHeight))
|
|
140
|
-
} catch (e: ArithmeticException) {
|
|
141
|
-
// do nothing, send progress as 0
|
|
142
|
-
}
|
|
143
|
-
Log.i(TAG, "DiffY: $diffY $height")
|
|
144
|
-
|
|
145
|
-
context
|
|
146
|
-
.getNativeModule(UIManagerModule::class.java)
|
|
147
|
-
?.eventDispatcher
|
|
148
|
-
?.dispatchEvent(KeyboardTransitionEvent(view.id, height, progress))
|
|
149
|
-
|
|
150
|
-
return insets
|
|
124
|
+
override fun onProgress(
|
|
125
|
+
insets: WindowInsetsCompat,
|
|
126
|
+
runningAnimations: List<WindowInsetsAnimationCompat>
|
|
127
|
+
): WindowInsetsCompat {
|
|
128
|
+
// onProgress() is called when any of the running animations progress...
|
|
129
|
+
|
|
130
|
+
// First we get the insets which are potentially deferred
|
|
131
|
+
val typesInset = insets.getInsets(deferredInsetTypes)
|
|
132
|
+
// Then we get the persistent inset types which are applied as padding during layout
|
|
133
|
+
val otherInset = insets.getInsets(persistentInsetTypes)
|
|
134
|
+
|
|
135
|
+
// Now that we subtract the two insets, to calculate the difference. We also coerce
|
|
136
|
+
// the insets to be >= 0, to make sure we don't use negative insets.
|
|
137
|
+
val diff = Insets.subtract(typesInset, otherInset).let {
|
|
138
|
+
Insets.max(it, Insets.NONE)
|
|
151
139
|
}
|
|
140
|
+
val diffY = (diff.top - diff.bottom).toFloat()
|
|
141
|
+
val height = toDp(diffY, context)
|
|
142
|
+
|
|
143
|
+
var progress = 0.0
|
|
144
|
+
try {
|
|
145
|
+
progress = Math.abs((height.toDouble() / persistentKeyboardHeight))
|
|
146
|
+
} catch (e: ArithmeticException) {
|
|
147
|
+
// do nothing, send progress as 0
|
|
148
|
+
}
|
|
149
|
+
Log.i(TAG, "DiffY: $diffY $height")
|
|
150
|
+
|
|
151
|
+
context
|
|
152
|
+
?.getNativeModule(UIManagerModule::class.java)
|
|
153
|
+
?.eventDispatcher
|
|
154
|
+
?.dispatchEvent(KeyboardTransitionEvent(view.id, height, progress))
|
|
155
|
+
|
|
156
|
+
return insets
|
|
157
|
+
}
|
|
152
158
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
5.6
|
package/ios/.swiftformat
ADDED
|
@@ -6,15 +6,15 @@
|
|
|
6
6
|
// Copyright © 2022 Facebook. All rights reserved.
|
|
7
7
|
//
|
|
8
8
|
|
|
9
|
+
import AVFoundation
|
|
9
10
|
import Foundation
|
|
10
11
|
import UIKit
|
|
11
|
-
import AVFoundation
|
|
12
12
|
|
|
13
13
|
@objc(KeyboardController)
|
|
14
14
|
class KeyboardController: RCTEventEmitter {
|
|
15
15
|
public static var shared: KeyboardController?
|
|
16
16
|
private var hasListeners = false
|
|
17
|
-
|
|
17
|
+
|
|
18
18
|
override class func requiresMainQueueSetup() -> Bool {
|
|
19
19
|
return false
|
|
20
20
|
}
|
|
@@ -25,29 +25,29 @@ class KeyboardController: RCTEventEmitter {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
// Android stubs
|
|
28
|
-
@objc func setInputMode(_
|
|
28
|
+
@objc func setInputMode(_: NSNumber!) {}
|
|
29
29
|
@objc func setDefaultMode() {}
|
|
30
|
-
|
|
31
|
-
@objc open
|
|
30
|
+
|
|
31
|
+
@objc override open func supportedEvents() -> [String] {
|
|
32
32
|
return [
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
"KeyboardController::keyboardWillShow",
|
|
34
|
+
"KeyboardController::keyboardDidShow",
|
|
35
|
+
"KeyboardController::keyboardWillHide",
|
|
36
|
+
"KeyboardController::keyboardDidHide",
|
|
37
37
|
]
|
|
38
38
|
}
|
|
39
|
-
|
|
40
|
-
@objc open
|
|
39
|
+
|
|
40
|
+
@objc override open func startObserving() {
|
|
41
41
|
hasListeners = true
|
|
42
42
|
}
|
|
43
|
-
|
|
44
|
-
@objc open
|
|
43
|
+
|
|
44
|
+
@objc override open func stopObserving() {
|
|
45
45
|
hasListeners = false
|
|
46
46
|
}
|
|
47
|
-
|
|
48
|
-
@objc open
|
|
49
|
-
if
|
|
50
|
-
|
|
47
|
+
|
|
48
|
+
@objc override open func sendEvent(withName name: String!, body: Any!) {
|
|
49
|
+
if hasListeners {
|
|
50
|
+
super.sendEvent(withName: name, body: body)
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
53
|
}
|
|
@@ -5,74 +5,102 @@ class KeyboardControllerViewManager: RCTViewManager {
|
|
|
5
5
|
}
|
|
6
6
|
|
|
7
7
|
override func view() -> (KeyboardControllerView) {
|
|
8
|
-
|
|
8
|
+
return KeyboardControllerView(frame: CGRect.zero, eventDispatcher: bridge.eventDispatcher())
|
|
9
9
|
}
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
class KeyboardControllerView
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
init(frame: CGRect, eventDispatcher: RCTEventDispatcherProtocol) {
|
|
17
|
-
self.eventDispatcher = eventDispatcher
|
|
18
|
-
super.init(frame: frame)
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
required init?(coder: NSCoder) {
|
|
22
|
-
fatalError("init(coder:) has not been implemented")
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
override func willMove(toWindow newWindow: UIWindow?) {
|
|
26
|
-
if (newWindow == nil) {
|
|
27
|
-
// Will be removed from a window
|
|
28
|
-
NotificationCenter.default.removeObserver(self)
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
override func didMoveToWindow() {
|
|
33
|
-
if (self.window != nil) {
|
|
34
|
-
// Added to a window
|
|
35
|
-
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillDisappear), name: UIResponder.keyboardWillHideNotification, object: nil)
|
|
36
|
-
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillAppear), name: UIResponder.keyboardWillShowNotification, object: nil)
|
|
37
|
-
NotificationCenter.default.addObserver(self, selector: #selector(keyboardDidAppear), name: UIResponder.keyboardDidShowNotification, object: nil)
|
|
38
|
-
NotificationCenter.default.addObserver(self, selector: #selector(keyboardDidDisappear), name: UIResponder.keyboardDidHideNotification, object: nil)
|
|
39
|
-
}
|
|
40
|
-
}
|
|
12
|
+
class KeyboardControllerView: UIView {
|
|
13
|
+
private var eventDispatcher: RCTEventDispatcherProtocol
|
|
14
|
+
@objc var onKeyboardMove: RCTDirectEventBlock?
|
|
41
15
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
16
|
+
init(frame: CGRect, eventDispatcher: RCTEventDispatcherProtocol) {
|
|
17
|
+
self.eventDispatcher = eventDispatcher
|
|
18
|
+
super.init(frame: frame)
|
|
19
|
+
}
|
|
45
20
|
|
|
46
|
-
|
|
21
|
+
@available(*, unavailable)
|
|
22
|
+
required init?(coder _: NSCoder) {
|
|
23
|
+
fatalError("init(coder:) has not been implemented")
|
|
24
|
+
}
|
|
47
25
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
26
|
+
override func willMove(toWindow newWindow: UIWindow?) {
|
|
27
|
+
if newWindow == nil {
|
|
28
|
+
// Will be removed from a window
|
|
29
|
+
// swiftlint:disable notification_center_detachment
|
|
30
|
+
NotificationCenter.default.removeObserver(self)
|
|
52
31
|
}
|
|
32
|
+
}
|
|
53
33
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
34
|
+
override func didMoveToWindow() {
|
|
35
|
+
if window != nil {
|
|
36
|
+
// Added to a window
|
|
37
|
+
NotificationCenter.default.addObserver(
|
|
38
|
+
self,
|
|
39
|
+
selector: #selector(keyboardWillDisappear),
|
|
40
|
+
name: UIResponder.keyboardWillHideNotification,
|
|
41
|
+
object: nil
|
|
42
|
+
)
|
|
43
|
+
NotificationCenter.default.addObserver(
|
|
44
|
+
self,
|
|
45
|
+
selector: #selector(keyboardWillAppear),
|
|
46
|
+
name: UIResponder.keyboardWillShowNotification,
|
|
47
|
+
object: nil
|
|
48
|
+
)
|
|
49
|
+
NotificationCenter.default.addObserver(
|
|
50
|
+
self,
|
|
51
|
+
selector: #selector(keyboardDidAppear),
|
|
52
|
+
name: UIResponder.keyboardDidShowNotification,
|
|
53
|
+
object: nil
|
|
54
|
+
)
|
|
55
|
+
NotificationCenter.default.addObserver(
|
|
56
|
+
self,
|
|
57
|
+
selector: #selector(keyboardDidDisappear),
|
|
58
|
+
name: UIResponder.keyboardDidHideNotification,
|
|
59
|
+
object: nil
|
|
60
|
+
)
|
|
60
61
|
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
@objc func keyboardWillAppear(_ notification: Notification) {
|
|
65
|
+
if let keyboardFrame: NSValue = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue {
|
|
66
|
+
let keyboardHeight = keyboardFrame.cgRectValue.size.height
|
|
67
|
+
|
|
68
|
+
eventDispatcher.send(
|
|
69
|
+
KeyboardMoveEvent(
|
|
70
|
+
viewTag: reactTag,
|
|
71
|
+
height: -keyboardHeight as NSNumber,
|
|
72
|
+
progress: 1
|
|
73
|
+
)
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
var data = [AnyHashable: Any]()
|
|
77
|
+
data["height"] = keyboardHeight
|
|
78
|
+
KeyboardController.shared?.sendEvent(withName: "KeyboardController::keyboardWillShow", body: data)
|
|
71
79
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
@objc func keyboardWillDisappear() {
|
|
83
|
+
eventDispatcher.send(KeyboardMoveEvent(viewTag: reactTag, height: 0, progress: 0))
|
|
84
|
+
|
|
85
|
+
var data = [AnyHashable: Any]()
|
|
86
|
+
data["height"] = 0
|
|
87
|
+
KeyboardController.shared?.sendEvent(withName: "KeyboardController::keyboardWillHide", body: data)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
@objc func keyboardDidAppear(_ notification: Notification) {
|
|
91
|
+
if let keyboardFrame: NSValue = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue {
|
|
92
|
+
let keyboardHeight = keyboardFrame.cgRectValue.size.height
|
|
93
|
+
|
|
94
|
+
var data = [AnyHashable: Any]()
|
|
95
|
+
data["height"] = keyboardHeight
|
|
96
|
+
|
|
97
|
+
KeyboardController.shared?.sendEvent(withName: "KeyboardController::keyboardDidShow", body: data)
|
|
77
98
|
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
@objc func keyboardDidDisappear() {
|
|
102
|
+
var data = [AnyHashable: Any]()
|
|
103
|
+
data["height"] = 0
|
|
104
|
+
KeyboardController.shared?.sendEvent(withName: "KeyboardController::keyboardDidHide", body: data)
|
|
105
|
+
}
|
|
78
106
|
}
|