React Native TextInput onFocus 不允许其他子组件的onPress

React Native TextInput onFocus does not allow onPress of other child components

嵌套的TextInput组件不允许调用其他组件的onPress函数。仅当 TextInput 未获得焦点时,onPress 才能正常工作。

React 本机版本:0.66.3

这是我的代码

export const Component = (props): JSX.Element {
  const { searchText, onChangeSearchText, onClearSearchText } = props
  const [searchViewFocused, setSearchViewFocused] = useState<boolean>(false)
  const searchIcon = searchViewFocused ? "searchActive" : "searchInactive"
  const cancelIcon = searchViewFocused ? "cancelActive" : "cancelInactive"
  return (
    <View style={styles.searchBoxContainer}>
      <View style={[styles.searchBox, searchViewFocused && styles.searchBarActive]}>
        <Icon styles={styles.searchIcon} icon={searchIcon} />
        <TextInput
          style={styles.searchInput}
          onChangeText={onChangeSearchText}
          value={searchText}
          onFocus={() => setSearchViewFocused(true)}
          onBlur={() => setSearchViewFocused(false)}
          autoCompleteType={"off"}
          numberOfLines={1}
        />
        {searchText !== "" && (
          <Pressable style={styles.clearIcon} onPress={onClearSearchText}>
            <Icon icon={cancelIcon} />
          </Pressable>
        )}
      </View>
    </View>
  )
})

附件是

的图片

预期。

VS

问题

当在聚焦状态下按下十字图标时,textInput 没有聚焦我想要实现的是搜索文本被清除并且输入保持聚焦。

注意:当输入未聚焦时,onPress 工作得很好

感谢任何帮助。谢谢!

PS:尝试了 TouchableOpacity 并且我还尝试将组件包装在 ScrollView 中以使用 keyboardShouldPersistTaps='handled',如 SO 答案之一所述,但没有成功。

您正在根据 TextInput 是否具有焦点来设置整个组件的焦点。由于清除按钮在文本输入之外,按下它会导致组件失去焦点。

一种解决方案是将 TextInput 实例存储在 ref 中。当按下清除按钮时,您可以重新聚焦文本输入。我在下面复制了您的组件并添加了一些新行,这些行已在注释中标记。

export const Component = (props): JSX.Element {
  const { searchText, onChangeSearchText, onClearSearchText } = props
  const textInputRef = useRef(null); // new
  const [searchViewFocused, setSearchViewFocused] = useState<boolean>(false)
  const searchIcon = searchViewFocused ? "searchActive" : "searchInactive"
  const cancelIcon = searchViewFocused ? "cancelActive" : "cancelInactive"
  const onClear = () => {
    onClearSearchText();
    textInputRef.current?.focus();
  } // new
  return (
    <View style={styles.searchBoxContainer}>
      <View style={[styles.searchBox, searchViewFocused && styles.searchBarActive]}>
        <Icon styles={styles.searchIcon} icon={searchIcon} />
        <TextInput
          ref={textInputRef} // new
          style={styles.searchInput}
          onChangeText={onChangeSearchText}
          value={searchText}
          onFocus={() => setSearchViewFocused(true)}
          onBlur={() => setSearchViewFocused(false)}
          autoCompleteType={"off"}
          numberOfLines={1}
        />
        {searchText !== "" && (
          <Pressable style={styles.clearIcon} onPress={onClear}> // calls new function
            <Icon icon={cancelIcon} />
          </Pressable>
        )}
      </View>
    </View>
  )
})

找到一个解决方法是将整个组件包装到 ScrollView 中并添加道具 keyboardShouldPersistTaps='handled'

之前,我将 Component 中的视图设为 ScrollView 并添加了 keyboardShouldPersistTaps='handled',但没有用

export const Component = (props): JSX.Element {
  ...
  return (
    <ScrollView contentContainerStyle={styles.searchBoxContainer} 
                keyboardShouldPersistTaps='handled'>
     ...
    </ScrollView>
  )
})

关键是将整个组件包裹在 ScrollView 中,

这是有效的方法:

<ScrollView keyboardShouldPersistTaps='handled'>
     <Component {...props}/>
</ScrollView>

我猜这是一个愚蠢的错误,但值得指出!