KeyboardInsetsView
KeyboardInsetsView
是一个 React Native 原生 UI 组件,用于处理软键盘遮挡输入框的问题。
KeyboardInsetsView
使用简单,自动模式下不需要额外代码来处理键盘。
本库主要依据 Android 官方指南 Synchronize animation with the software keyboard 来实现,同时参考了 react-native-keyboard-controller。因为该库不是很符合我的需求,所以我自己写了一个。
Installation
yarn add @sdcx/keyboard-insets
iOS
cd ios
pod install
Android
开启 edge-to-edge。 这将使得 APP 的 UI 撑满整个屏幕,而不是被系统 UI(譬如虚拟导航键)遮挡,从而实现更摩登的 UI 效果。
import androidx.core.view.WindowCompat;
public class MainActivity extends ReactActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(null);
WindowCompat.setDecorFitsSystemWindows(getWindow(), false);
}
}
为了更好的向后(Android 10 以前)兼容, 在 AndroidManifest 中设置 android:windowSoftInputMode="adjustResize"
。
<activity
android:name=".MainActivity"
...
android:windowSoftInputMode="adjustResize">
<intent-filter>
...
</intent-filter>
</activity>
开启 Edge-to-Edge 后,你的 UI 会撑满整个屏幕,可使用 react-native-safe-area-context 来处理和系统 UI (譬如虚拟导航键) 重叠的部分。
可参考以下代码进行全局处理,也可以每个页面单独处理,以实现更美观更摩登的 UI 效果。
import { Platform } from 'react-native'
import { SafeAreaProvider, SafeAreaView } from 'react-native-safe-area-context'
function App() {
return (
<SafeAreaProvider>
<NavigationContainer>...</NavigationContainer>
{Platform.OS === 'android' && <SafeAreaView mode="margin" edges={['bottom']} />}
</SafeAreaProvider>
)
}
如果使用 hybrid-navigation 作为导航组件,则不需要做任何事情,因为它已经帮你处理好了。
Usage
使用 KeyboardInsetsView
代替 View
作为容器,或者使用 KeyboardInsetsView
将 ScrollView
包裹起来。当键盘显示或隐藏时,KeyboardInsetsView
会自动调整自身的位置,以保证输入框不被键盘遮挡。
import { KeyboardInsetsView } from '@sdcx/keyboard-insets'
function MyComponent() {
return (
<KeyboardInsetsView extraHeight={16} style={{ flex: 1 }}>
<ScrollView>
...
<TextInput />
...
</ScrollView>
</KeyboardInsetsView>
)
}
Support Nested.
import { KeyboardInsetsView } from '@sdcx/keyboard-insets'
function MyComponent() {
return (
<KeyboardInsetsView extraHeight={16} style={{ flex: 1 }}>
...
<KeyboardInsetsView extraHeight={8}>
<TextInput />
</KeyboardInsetsView>
...
</KeyboardInsetsView>
)
}
KeyboardInsetsView
本质上是个 View
,所以你可以使用 View
的所有属性,也可以和 View
互相替换。
KeyboardInsetsView
仅有少量几个属性:
-
extraHeight
:自动模式下,键盘总是紧贴着输入框的下边缘,这个属性设置输入框距离键盘的额外高度。KeyboardInsetsView 的最大偏移受键盘高度限制,若加入额外高度后,KeyboardInsetsView 偏移距离大于键盘高度,将产生截断,此时 KeyboardInsetsView 偏移距离等于键盘高度,底部将与键盘顶部相贴
-
explicitly
:仅对 iOS 生效,自动模式下,是否显式地跟随键盘位置变化。默认为 false
,通过隐式动画来处理。
-
onKeyboard
:是个回调函数,一旦设置,就进入手动模式,KeyboardInsetsView
不会帮你调整输入框的位置。你需要利用这个回调函数实现自己想要的效果。
onKeyboard
的参数声明如下:
interface KeyboardState {
height: number
shown: boolean
transitioning: boolean
position: Animated.Value
}
API
-
useKeyboard
为了方便用户编写 onKeyboard
回调,keyboard-insets 提供了一个 useKeyboard
hook,使用方法如下:
import { useKeyboard } from '@sdcx/keyboard-insets'
function MyComponent() {
const { keyboard, onKeyboard } = useKeyboard()
console.log(keyboard.height),
return (
<KeyboardInsetsView onKeyboard={onKeyboard}>
<TextInput />
</KeyboardInsetsView>
)
}
-
getEdgeInsetsForView
有时候你需要知道某个 View
距离屏幕四边的距离,这个时候就可以使用 getEdgeInsetsForView
方法。
import { getEdgeInsetsForView } from '@sdcx/keyboard-insets'
function MyComponent() {
const inputRef = useRef<TextInput>(null)
const onLayout = useCallback(() => {
const viewTag = findNodeHandle(inputRef.current)
if (viewTag === null) {
return
}
getEdgeInsetsForView(viewTag, insets => {
console.log('insets', insets)
})
}, [])
return (
<View>
<TextInput ref={inputRef} onLayout={onLayout} />
</View>
)
}
Caution
如果你在项目中同时使用了react-native-bars,那么在初始化它的时候,需要把它内置的键盘处理逻辑关闭:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
RNBars.init(this, "dark-content", false);
}