键盘处理
编辑
处理Android或iOS设备上常见键盘交互的指南。
键盘处理对于在您的 Expo 应用中创建出色的用户体验至关重要。React Native 提供了 Keyboard 和 KeyboardAvoidingView,这些组件通常用于处理键盘事件。对于更复杂或自定义的键盘交互,您可以考虑使用 react-native-keyboard-controller,这是一个提供高级键盘处理功能的库。
本指南涵盖了常见的键盘交互及其有效管理方法。

在这个React Native应用的键盘处理教程中,您将学习如何解决键盘在您尝试在应用中输入时遮盖输入框的问题。
键盘处理基础
以下部分解释如何使用常见API处理键盘交互。
键盘避免视图
KeyboardAvoidingView 是一个组件,它会根据键盘的高度自动调整视图的高度、位置或底部填充,以便在键盘显示时保持可见。
Android 和 iOS 对 behavior 属性的交互方式不同。在 iOS 中,通常使用 padding 是最有效的,而在Android中,仅仅使用 KeyboardAvoidingView 就可以防止输入框被覆盖。这就是以下示例在 Android 中使用 undefined 的原因。尝试不同的 behavior 选项是个好习惯,因为不同的选项可能适合您的应用。
import { KeyboardAvoidingView, TextInput } from 'react-native'; export default function HomeScreen() { return ( <KeyboardAvoidingView behavior={Platform.OS === 'ios' ? 'padding' : undefined} style={{ flex: 1 }}> <TextInput placeholder="Type here..." /> </KeyboardAvoidingView>; ); }
在上面的示例中,KeyboardAvoidingView 的高度会根据设备的键盘高度自动调整,这确保了输入框始终可见。
在 Android 上使用底部标签导航器时,您可能会注意到聚焦输入字段会导致底部标签被推到键盘上方。为了解决此问题,请在 app config 的Android配置中添加 softwareKeyboardLayoutMode 属性,并将其设置为 pan。
"expo" { "android": { "softwareKeyboardLayoutMode": "pan" } }
添加此属性后,重新启动开发服务器并重新加载您的应用以应用更改。
还可以使用 tabBarHideOnKeyboard 在键盘打开时隐藏底部标签。这是底部标签导航器的一项选项。如果设置为 true,将在键盘打开时隐藏标签栏。
import { Tabs } from 'expo-router'; export default function TabLayout() { return ( <Tabs screenOptions={{ tabBarHideOnKeyboard: true, }}> <Tabs.Screen name="index" /> </Tabs> ); }
键盘事件
React Native 中的 Keyboard 模块允许您监听本机事件,对其做出反应,并对键盘进行更改,例如退出键盘。
要监听键盘事件,请使用 Keyboard.addListener 方法。此方法接受一个事件名称和一个回调函数作为参数。当键盘显示或隐藏时,回调函数将与事件数据一起调用。
以下示例说明了添加键盘监听器的用例。状态变量 isKeyboardVisible 在每次键盘显示或隐藏时切换。根据此变量,按钮允许用户仅在键盘处于活动状态时关闭键盘。此外,请注意按钮使用了 Keyboard.dismiss 方法。
import { useEffect, useState } from 'react'; import { Keyboard, View, Button, TextInput } from 'react-native'; export default function HomeScreen() { const [isKeyboardVisible, setIsKeyboardVisible] = useState(false); useEffect(() => { const showSubscription = Keyboard.addListener('keyboardDidShow', handleKeyboardShow); const hideSubscription = Keyboard.addListener('keyboardDidHide', handleKeyboardHide); return () => { showSubscription.remove(); }; }, []); const handleKeyboardShow = event => { setIsKeyboardVisible(true); }; const handleKeyboardHide = event => { setIsKeyboardVisible(false); }; return ( <View> {isKeyboardVisible && <Button title="Dismiss keyboard" onPress={Keyboard.dismiss} />} <TextInput placeholder="Type here..." /> </View> ); }
使用键盘控制器进行高级键盘处理
对于更复杂的键盘交互,例如包含多个文本输入字段的大型可滚动输入表单,请考虑使用 react-native-keyboard-controller (键盘控制器) 库。它提供的功能超出了内置的React Native键盘API,提供了一致的Android和iOS体验,配置较少,并提供用户所期望的原生感觉。
先决条件
以下步骤使用 开发构建 描述,因为键盘控制器库未包含在Expo Go中。有关更多信息,请参见 创建开发构建。
键盘控制器 还需要 react-native-reanimated 正常工作。要安装它,请遵循这些 安装说明。
安装
首先在您的Expo项目中安装键盘控制器库:
- npx expo install react-native-keyboard-controller设置提供程序
要完成设置,请将 KeyboardProvider 添加到您的应用中。
import { Stack } from 'expo-router'; import { KeyboardProvider } from 'react-native-keyboard-controller'; export default function RootLayout() { return ( <KeyboardProvider> <Stack> <Stack.Screen name="home" /> <Stack.Screen name="chat" /> </Stack> </KeyboardProvider> ); }
处理多个输入
KeyboardAvoidingView 组件非常适合原型设计,但它需要特定于平台的配置,且不易自定义。
作为更强大的替代方案,您可以使用 KeyboardAwareScrollView 组件。它会自动滚动到聚焦的 TextInput,并提供类似原生的性能。对于只有几个元素的简单屏幕,使用 KeyboardAwareScrollView 是一个不错的方法。
对于具有多个输入的屏幕,键盘控制器库还提供了 KeyboardToolbar 组件,可以与 KeyboardAwareScrollView 一起使用。它们共同处理输入导航,并防止键盘覆盖屏幕,而无需自定义配置:
import { TextInput, View, StyleSheet } from 'react-native'; import { KeyboardAwareScrollView, KeyboardToolbar } from 'react-native-keyboard-controller'; export default function FormScreen() { return ( <> <KeyboardAwareScrollView bottomOffset={62} contentContainerStyle={styles.container}> <View> <TextInput placeholder="Type a message..." style={styles.textInput} /> <TextInput placeholder="Type a message..." style={styles.textInput} /> </View> <TextInput placeholder="Type a message..." style={styles.textInput} /> <View> <TextInput placeholder="Type a message..." style={styles.textInput} /> <TextInput placeholder="Type a message..." style={styles.textInput} /> <TextInput placeholder="Type a message..." style={styles.textInput} /> </View> <TextInput placeholder="Type a message..." style={styles.textInput} /> </KeyboardAwareScrollView> <KeyboardToolbar /> </> ); } const styles = StyleSheet.create({ container: { gap: 16, padding: 16, }, listStyle: { padding: 16, gap: 16, }, textInput: { width: 'auto', flexGrow: 1, flexShrink: 1, height: 45, borderWidth: 1, borderRadius: 8, borderColor: '#d8d8d8', backgroundColor: '#fff', padding: 8, marginBottom: 8, }, });
上述示例将输入框包装在 KeyboardAwareScrollView 中,以防止键盘覆盖它们。KeyboardToolbar 组件显示导航控件和关闭按钮。尽管它可以在没有配置的情况下工作,但您可以根据需要自定义工具栏内容。
根据键盘高度同步动画视图
对于更加高级和可定制的方法,您可以使用 useKeyboardHandler。它提供对键盘生命周期事件的访问。它允许我们确定键盘何时开始动画,以及其在动画每一帧中的位置。
使用 useKeyboardHandler 钩子,您可以创建一个自定义钩子,以便在每一帧中访问键盘的高度。它使用来自reanimated的 useSharedValue 返回高度,如下所示。
import { useKeyboardHandler } from 'react-native-keyboard-controller'; import Animated, { useAnimatedStyle, useSharedValue } from 'react-native-reanimated'; const useGradualAnimation = () => { const height = useSharedValue(0); useKeyboardHandler( { onMove: event => { 'worklet'; height.value = Math.max(event.height, 0); }, }, [] ); return { height }; };
您可以使用 useGradualAnimation 钩子来动画一个视图,并在键盘处于活动或解除状态时给它一个平滑的动画,例如在聊天屏幕组件(在下面的示例中显示)。该组件从钩子中获取键盘高度。接着,它使用来自reanimated的 useAnimatedStyle 钩子创建一个名为 fakeView 的动画样式。该样式仅包含一个属性:height,其设置为键盘的高度。
fakeView 动画样式在 TextInput 之后的动画视图中使用。该视图的高度将在每一帧中根据键盘的高度进行动画,从而有效地将内容推送到键盘上方,并在键盘被关闭时将其高度减少到零。
import { StyleSheet, Platform, FlatList, View, StatusBar, TextInput } from 'react-native'; import Animated, { useAnimatedStyle, useSharedValue } from 'react-native-reanimated'; import { useKeyboardHandler } from 'react-native-keyboard-controller'; import MessageItem from '@/components/MessageItem'; import { messages } from '@/messages'; const useGradualAnimation = () => { %%placeholder-start%%// 代码与之前的示例相同 %%placeholder-end%% }; export default function ChatScreen() { const { height } = useGradualAnimation(); const fakeView = useAnimatedStyle(() => { return { height: Math.abs(height.value), }; }, []); return ( <View style={styles.container}> <FlatList data={messages} renderItem={({ item }) => <MessageItem message={item} />} keyExtractor={item => item.createdAt.toString()} contentContainerStyle={styles.listStyle} /> <TextInput placeholder="Type a message..." style={styles.textInput} /> <Animated.View style={fakeView} /> </View> ); } const styles = StyleSheet.create({ container: { flex: 1, paddingTop: Platform.OS === 'android' ? StatusBar.currentHeight : 0, }, listStyle: { padding: 16, gap: 16, }, textInput: { width: '95%', height: 45, borderWidth: 1, borderRadius: 8, borderColor: '#d8d8d8', backgroundColor: '#fff', padding: 8, alignSelf: 'center', marginBottom: 8, }, });
其他资源
查看GitHub上的示例项目源代码。
react-native-keyboard-controller有关键盘控制器库的更多详细信息,请参见文档。