ReactNative安卓软键盘挤压视图解决方案
在AndroidManifest.xml 中通过添加 windowSoftInputMode属性 或者在代码中通过 getWindow方法拿到window实例来动态修改windowSoftInputMode都可以设置键盘弹起后是否调整窗口或视图来避免软键盘遮住输入框。
- adjustNothing
不调整界面或窗口、此时输入框所处位置低于键盘高度,则软键盘弹出后将会遮盖这输入框。
⚠️设置该值时将无法监听键盘显示隐藏事件。
Android Native有个hackable方法来实现监听、主要思路就是创建一个自定义浮层窗口 (宽0,高度和父视图一致match_parent) 继承自 PopupWindow 并且 实现 OnGlobalLayoutListener 。 该窗口里设置 windowSoftMode 为 adjustResize 或者adjustPan 从而可以监听键盘事件 。 在MainActivity中初始化该自定义 popupwindow,在其构造方法或自定义方法中拿到rootView,添加视图变化监听器 rootView.getViewTreeObserver(). addOnGlobalLayoutListener(this) 。 最后在实现的 onGlobalLayout 方法就可以计算变化前后的视图高度来拿到 键盘高度 和 键盘隐藏显示事件。该方法不值得推荐。
- adjustResize
不移动整体窗口,通过挤压窗口内部的视图、即将底部视图往上推,上方视图保持不变,挤压中间空间。从而实现避免遮挡原本会被遮住的输入框。
✅可以监听键盘隐藏事件。
- adjustPan
有需要的话移动整体窗口,往上方移动。从而将输入框推至键盘上方、避免遮挡输入框。如果输入框本身在键盘弹出后的上方、没有被键盘遮住,则不会移动窗口。
✅可以监听键盘隐藏事件。
那么既要可以监听键盘变化事件、又要保持除输入框之外的视图原位不变。这里可以利用 adjustPan 的特性 - 输入框本身在键盘上方则不调整窗口。
- 修改manifest中的 windowSoftMode 为 adjustPan
- 将真正的 TextInput 组件初始位置放在屏幕上方 (初始为完全透明),占位 TextInput (实际上是Text组件 )组件在下方。键盘弹起后同步位移占位输入框 和 真正的 TextInput组件,当占位输入框动画结束了就设置真正的 TextInput组件透明度为 1.0 。至此就完整实现了预想效果。
代码结构:
...
useKeyboardDidShowWithCallback(
(event) => {
inputTransY.value = inputBottom - event.endCoordinates.height;
inputPlaceholderTransY.value = withSpring(-event.endCoordinates.height,{mass:0.5,stiffness:220,damping:20},(finished) => {
inputOpacity.value = 1.0;
inputPlaceholderOpacity.value = 0;
})
},
(event) => {
inputTransY.value = withTiming(-inputBottom);
}, true);
return (
<View style={{ flex: 1, justifyContent: 'flex-end' }}>
<Animated.View style={[styles.absolute]}>
<CommentTextInputer kind="input" inputRef={inputRef}/>
</Animated.View>
<Animated.View style={[styles.absolute]} >
<CommentTextInputer kind="text" />
</Animated.View>
</View>
)
...