ScrollView内嵌TouchableOpacity首次点击无响应如何实现单次触发?
我已经查阅过该主题的相关同类问题,请不要急于关闭此问题。
我开发了一个搜索页面,输入搜索词后会拉取对应的结果列表。拉取完成后我希望点击任意一条结果即可跳转到该对象的详情页,但目前首次点击始终无法被检测到,只有第二次点击才能生效。我的组件代码如下:
return ( <View> <TextInput value={query} placeholder="Type Here..." onChangeText={(search) => setQuery(search)} /> {fetching ? ( <Spinner visible={fetching} textContent={'Fetching data...'} textStyle={{ fontSize: 14 }} /> ) : null} {items ? ( <ScrollView keyboardShouldPersistTaps={true}> <FlatList numColumns={1} horizontal={false} data={items} keyExtractor={(item) => item.id} renderItem={({ item }) => ( <TouchableOpacity onPress={() => navigation.navigate('Item Details', { id: item.id }) }> <ItemDisplay item={item} keyboardShouldPersistTaps="always" /> </TouchableOpacity> )} /> </ScrollView> ) : null} </View> );
我的ItemDisplay组件仅用于展示一行包含条目图片和条目ID的内容,无特殊逻辑。
按照同类问题的解决方案建议,我已经给<ScrollView keyboardShouldPersistTaps={true}>设置了对应属性,也给<ItemDisplay item={item} keyboardShouldPersistTaps="always" />传入了对应配置,但问题仍然没有解决,我还是需要点击两次才能触发跳转。请问有什么方法可以修复这个问题?我是在安卓端进行测试的,供参考。
我也尝试过给ScrollView配置keyboardDismissMode="on-drag" keyboardShouldPersistTaps={"always"},同样没有生效。
问题原因
你的问题是嵌套滚动组件导致的键盘事件冲突:FlatList本身自带滚动能力,你额外在外层套了ScrollView,两个滚动组件的键盘焦点处理逻辑互相冲突,导致你设置的keyboardShouldPersistTaps没有真正生效,第一次点击被系统用来回收键盘焦点,第二次点击才会触发TouchableOpacity的事件。
修复步骤
- 移除冗余的外层ScrollView,将
keyboardShouldPersistTaps属性直接配置在FlatList上,安卓端推荐使用handled值,兼容性比always更好 - 给TextInput添加
blurOnSubmit={true}属性,输入完成后自动收起键盘,避免焦点残留 - 不需要给普通展示组件ItemDisplay传
keyboardShouldPersistTaps属性,该属性仅对滚动类组件生效,传给普通组件没有任何作用 - 如果调整后仍有问题,可以将TouchableOpacity的
onPress替换为onPressIn,优先响应按下事件,避开焦点抢占逻辑
修改后参考代码
return ( <View> <TextInput value={query} placeholder="Type Here..." onChangeText={(search) => setQuery(search)} blurOnSubmit={true} /> {fetching ? ( <Spinner visible={fetching} textContent={'Fetching data...'} textStyle={{ fontSize: 14 }} /> ) : null} {items ? ( <FlatList numColumns={1} horizontal={false} data={items} keyExtractor={(item) => item.id} keyboardShouldPersistTaps="handled" renderItem={({ item }) => ( <TouchableOpacity onPress={() => navigation.navigate('Item Details', { id: item.id }) }> <ItemDisplay item={item} /> </TouchableOpacity> )} /> ) : null} </View> );
如果你的页面确实需要外层滚动容器包裹多个模块,保留ScrollView的同时需要将两个滚动组件的keyboardShouldPersistTaps都设置为handled即可。
内容的提问来源于stack exchange,提问作者newbie coder

