如何在弹出Modal时保持TextInput的焦点状态?
问题描述
我有一个TextInput组件,需要显示在所有界面之上,且在弹出Modal时仍保持焦点状态。目前已实现将该TextInput显示在所有界面上层,但弹出Modal时它会失去焦点。

原代码:
import { NavigationContainer } from '@react-navigation/native' import React from 'react' import { Button, Text, TextInput, View } from 'react-native' import { createStackNavigator } from '@react-navigation/stack' import { createNativeStackNavigator } from '@react-navigation/native-stack' export { navigationRef } from './utils/navigation' export function App() { return ( <> <MyView /> <NavigationContainer> <RootStackScreen /> </NavigationContainer> </> ) } export default App function HomeScreen({ navigation }) { return ( <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}> <Text style={{ fontSize: 30 }}>This is the home screen!</Text> <Button onPress={() => navigation.navigate('MyModal')} title="Open Modal" /> </View> ) } function DetailsScreen() { return ( <View> <Text>Details</Text> </View> ) } function ModalScreen({ navigation }) { return ( <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}> <Text style={{ fontSize: 30 }}>This is a modal!</Text> <Button onPress={() => navigation.goBack()} title="Dismiss" /> </View> ) } const RootStack = createStackNavigator() function RootStackScreen() { return ( <RootStack.Navigator> <RootStack.Group> <RootStack.Screen name="Home" component={HomeScreen} /> <RootStack.Screen name="Details" component={DetailsScreen} /> </RootStack.Group> <RootStack.Group screenOptions={{ presentation: 'modal' }}> <RootStack.Screen name="MyModal" component={ModalScreen} /> </RootStack.Group> </RootStack.Navigator> ) } function MyView() { return ( <View style={{ position: 'absolute', zIndex: 999999999999999, left: 0, top: 230, right: 0 }}> <TextInput placeholder="textInput" autoFocus style={{ borderWidth: 4, width: '100%', height: 50, marginTop: 90 }} /> </View> ) }
解决方案
核心思路是监听导航状态变化,在Modal弹出后手动恢复TextInput的焦点:
- 给TextInput添加ref,用于手动控制焦点
- 通过导航监听事件,检测Modal的显示状态
- 当Modal弹出时,调用TextInput的
focus()方法恢复焦点
修改后的MyView组件代码:
import { useRef, useEffect } from 'react'; import { TextInput, View } from 'react-native'; import { navigationRef } from './utils/navigation'; function MyView() { const inputRef = useRef(null); useEffect(() => { // 监听导航状态变化 const unsubscribe = navigationRef.addListener('state', () => { const currentState = navigationRef.getState(); // 判断当前是否显示MyModal const isModalVisible = currentState.routes.some(route => route.name === 'MyModal'); if (isModalVisible && inputRef.current) { // 延迟执行确保Modal渲染完成,避免焦点被抢占 setTimeout(() => { inputRef.current.focus(); }, 100); } }); // 组件卸载时取消监听 return unsubscribe; }, []); return ( <View style={{ position: 'absolute', zIndex: 999999, left: 0, top: 230, right: 0 }}> <TextInput ref={inputRef} placeholder="textInput" autoFocus style={{ borderWidth: 4, width: '100%', height: 50, marginTop: 90 }} /> </View> ); }
说明
- React Navigation弹出Modal时,系统会自动将焦点转移到Modal所在层级,导致原TextInput失焦。通过监听导航状态变化,在Modal弹出后手动调用
focus()可以强制恢复焦点。 - 延迟100ms执行是为了确保Modal已经完成渲染,避免焦点被Modal的元素抢占。
- 保持
MyView的绝对定位和高zIndex,确保它始终显示在所有界面之上。
内容的提问来源于stack exchange,提问作者david_adler
相关产品推荐
相关产品推荐

