You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在弹出Modal时保持TextInput的焦点状态?

问题描述

我有一个TextInput组件,需要显示在所有界面之上,且在弹出Modal时仍保持焦点状态。目前已实现将该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的焦点:

  1. 给TextInput添加ref,用于手动控制焦点
  2. 通过导航监听事件,检测Modal的显示状态
  3. 当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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 16:45:44