【react native】ScrollView的触摸事件与TouchableWithoutFeedback的点击事件冲突

需求背景

使用 ScrollView 组件实现轮播图效果,该轮播图可以自动向右滑动。有下面两个需求:

(1)希望用户左右点击的时候,视图可以向左/向右滚动;

(2)希望用户触摸在屏幕的时候,轮播图不自动滚动,放开的时候重新计时5秒后向右滚动;

(3)在轮播视图内有一个按钮,希望我们在点击按钮并弹出弹窗的时候,轮播图停止计时,弹窗关闭后再重新计时。

需求分析

(1)我们可以使用 TouchableWithoutFeedback 组件,分别覆盖左右视图,当触发onPress的时候进行翻页。

(2)可以使用 ScrollViewonTouchStartonTouchEnd 事件,分别表示触摸开始和触摸结束时候的回调。

(3)事件的回调顺序是: onTouchStart > onPress > onTouchEnd ,所以下面的这种写法会导致,当点击share按钮的时候,打印如下:

javascript 复制代码
onTouchStart
click button, start to stop timer
onTouchEnd
// 执行完异步操作后会打印
start to start timer

但我们希望的是,能够打印如下:

javascript 复制代码
onTouchStart
click button, start to stop timer
// onTouchEnd 不打印
// 执行完异步操作后会打印
start to start timer
javascript 复制代码
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。

javascript 复制代码
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>
  );
}
相关推荐
熊猫_豆豆2 小时前
一个模拟四轴飞行器在随机气流扰动下悬停飞行的交互式3D仿真网页,包含飞行器建模与PID控制算法
javascript·3d·html·四轴无人机模拟飞行
来恩10033 小时前
jQuery选择器
前端·javascript·jquery
前端繁华如梦4 小时前
树上挂苹果还是挂玻璃球?Three.js 程序化果实的完整实现指南
前端·javascript
CDwenhuohuo4 小时前
优惠券组件直接用 uview plus
前端·javascript·vue.js
川冰ICE5 小时前
TypeScript装饰器与元编程实战
前端·javascript·typescript
AI砖家5 小时前
Vue3组件传参大全,各种传参方式的对比
前端·javascript·vue.js
希望永不加班5 小时前
var局部变量类型推断的利弊
java·服务器·前端·javascript·html
threelab5 小时前
Three.js 3D 地图可视化 | 三维可视化 / AI 提示词
前端·javascript·人工智能·3d·着色器
失眠的咕噜6 小时前
PDA 安卓设备上传多张图片
android·前端·javascript
掰头战士6 小时前
深入了解JS原型及原型继承链机制
javascript