【react native】ScrollView的触摸事件与TouchableWithoutFeedback的点击事件冲突
需求背景
使用 ScrollView 组件实现轮播图效果,该轮播图可以自动向右滑动。有下面两个需求:
(1)希望用户左右点击的时候,视图可以向左/向右滚动;
(2)希望用户触摸在屏幕的时候,轮播图不自动滚动,放开的时候重新计时5秒后向右滚动;
(3)在轮播视图内有一个按钮,希望我们在点击按钮并弹出弹窗的时候,轮播图停止计时,弹窗关闭后再重新计时。
需求分析
(1)我们可以使用 TouchableWithoutFeedback
组件,分别覆盖左右视图,当触发onPress
的时候进行翻页。
(2)可以使用 ScrollView
的 onTouchStart
和 onTouchEnd
事件,分别表示触摸开始和触摸结束时候的回调。
(3)事件的回调顺序是: onTouchStart
> onPress
> onTouchEnd
,所以下面的这种写法会导致,当点击share按钮的时候,打印如下:
onTouchStart
click button, start to stop timer
onTouchEnd
// 执行完异步操作后会打印
start to start timer
但我们希望的是,能够打印如下:
onTouchStart
click button, start to stop timer
// onTouchEnd 不打印
// 执行完异步操作后会打印
start to start timer
state = {
scrollViewTouchable: true,
};
handleSharePress = async() => {
// 停止定时器
console.log('click button, start to stop timer');
this.handleStopTimer();
// 处理 "Share" 按钮的逻辑
// await ....
// 打开定时器
console.log('start to start timer');
this.handleStartTimer();
};
render() {
const { scrollViewTouchable } = this.state;
return (
<View>
<ScrollView
onTouchStart={scrollViewTouchable ? ()=>{this.handleStartTimer(); console.log('onTouchStart')} : undefined}
onTouchEnd={scrollViewTouchable ? ()=>{this.handleStopTimer(); console.log('onTouchEnd')} : undefined}
// 其他属性...
>
{/* ScrollView 内容 */}
<TouchableOpacity
onPress={this.handleSharePress}
>
<View style={styles.shareButton}>
{/* Share 按钮内容 */}
</View>
</TouchableOpacity>
</ScrollView>
</View>
);
}
解决方法
通过阻止默认事件的方式好像不能解决上述问题,因为 TouchableWithoutFeedback 组件不会阻止事件冒泡到父组件。
所以我们考虑用一个state变量来控制 ScrollView 组件的触摸事件是否可用。在点击 “Share” 按钮时,将状态变量设置为 false,在 onPress 事件完成后,将状态变量设置回 true。
state = {
scrollViewTouchable: true,
};
handleSharePress = async() => {
this.setState({ scrollViewTouchable: false });
// 处理 "Share" 按钮的逻辑
// await...
this.setState({ scrollViewTouchable: true });
};
render() {
const { scrollViewTouchable } = this.state;
return (
<View>
<ScrollView
onTouchStart={scrollViewTouchable ? this.handleStartTimer : undefined}
onTouchEnd={scrollViewTouchable ? this.handleStopTimer : undefined}
// 其他属性...
>
{/* ScrollView 内容 */}
<TouchableOpacity
onPress={this.handleSharePress}
>
<View style={styles.shareButton}>
{/* Share 按钮内容 */}
</View>
</TouchableOpacity>
</ScrollView>
</View>
);
}