react-native拖拽体验优化

this.panResponder = PanResponder.create({
  /***************** 要求成为响应者 *****************/
  // 单机手势是否可以成为响应者
  onStartShouldSetPanResponder: (evt, gestureState) => true,
  // 移动手势是否可以成为响应者
  onMoveShouldSetPanResponder: (evt, gestureState) => true,
  // 拦截子组件的单击手势传递,是否拦截
  onStartShouldSetPanResponderCapture: (evt, gestureState) => true,
  // 拦截子组件的移动手势传递,是否拦截
  onMoveShouldSetPanResponderCapture: (evt, gestureState) => true,
  /***************** 响应者事件回调处理 *****************/
  // 单击手势监听回调
  onPanResponderGrant: (e, gestureState) => {
    console.log('onPanResponderGrant==>' + '单击手势申请成功,开始处理手势');
    this._onPanResponderGrant(e);
  },
  // 移动手势监听回调
  onPanResponderMove: throttle((e, gestureState) => {
    console.log('onPanResponderMove==>' + '移动手势申请成功,开始处理手势' + `${gestureState}`);
    this._onPanResponderMove(e, gestureState);
  }, 200),
  // 手势动作结束回调
  onPanResponderEnd: (evt, gestureState) => {
    console.log('onPanResponderEnd==>' + '手势操作完成了,用户离开');
    this._onPanResponderEnd(evt);
  },
  // 手势释放, 响应者释放回调
  onPanResponderRelease: (e, gestureState) => {
    // 用户放开了所有的触摸点,且此时视图已经成为了响应者。
    // 一般来说这意味着一个手势操作已经成功完成。
    this._onPanResponderRelease(e, gestureState);
    console.log('onPanResponderRelease==>' + '放开了触摸,手势结束');
  },
  // 手势申请失败,未成为响应者的回调
  onResponderReject: (e, gestureState) => {
    // 申请失败,其他组件未释放响应者
    console.log('onResponderReject==>' + '响应者申请失败');
    this._onPanResponderRelease(e, gestureState);
  },
  // 当前手势被强制取消的回调
  onPanResponderTerminate: e => {
    // 另一个组件已经成为了新的响应者,所以当前手势将被取消
    console.log('onPanResponderTerminate==>' + '由于某些原因(系统等),所以当前手势将被取消');
    return true;
  },
  onShouldBlockNativeResponder: (evt, gestureState) => {
    return true;
  }
});
  

需求是多个可以拖拽的对象所以需要知道每次是拖拽哪个,而调用方法需要用 {...this.panResponder.panHandlers}解构之后得到的json通过props传递给组件,使得组件变成响应者,打印{...this.panResponder.panHandlers}

[图片上传失败...(image-3e7074-1580929245556)]

多个拖拽就不能知道是哪个变成了响应者

  1. 不用解构,给View绑定事件,传递index

Animated.View绑定事件,如

 this.onResponderMove(index, nativeEvent, gestureState}
>

将index作为参数传递过去就知道是哪项作为了响应者,但是,参数中gestureState是undefined

[图片上传失败...(image-5cb757-1580929245556)]

官网中说:它提供了一个对触摸响应系统响应器的可预测的包装。对于每一个处理函数,它在原生事件之外提供了一个新的gestureState对象。

所以不用PanResponder.create得不到gestureState对象

2.通过重写解构出来的{...this.panResponder}后的onResponderGrant将index放到state中

List.map(li => (
     {
        this.touchY = e.nativeEvent.locationY - 12;
        this.initHeight = ((li.end - li.start) / 1800) * initOneHeight;
        this.dragItem = li;
        this.setState({
          isMove: true,
          movingHeight: this.initHeight,
          dragIndex: index
        });
      }}
    >
    
))

项目中使用了第二种方法,因为拖拽时需要得到gestureState对象

[站外图片上传中...(image-ff863f-1580929245556)]

 {
    this.areaScrollView = view;
  }}
>
    
        {
            scheduleList.map((li, index) => ())
        }
    
    
        {
            scheduleList.map((li, index) => ())
        }
    
    
        {
            scheduleSelectList.map((li, index) => ())
        }
    


ScrollView的children有3个View,scheduleList是0-24小时的间距,lineWrap是今天线,绝对定位,scheduleSelectList是选中的时间段,绝对定位。

android中的坑

[图片上传失败...(image-8bd84e-1580929245556)]


[图片上传失败...(image-d90c41-1580929245556)]

在android里面只有1/4的区域能够点击,ios没事,截图中绿色和黄色的交界处才能点击。原来只有图标能点击(圆圈灰色X,2424),在手机中点击体验不好,改成黄色区域能够点击(5050),因为黄色删除按钮和拖动按钮都是绝对定位,通过拖动,动态设置box(蓝色区域)的height。

box{
    position: 'absolute',
    top,
    height
}

蓝色区域外的区域点击在android中无效

解决方案

 // 青色区域,top - 25, 高度 + 50
     // 内部边框区域 margin 25


[图片上传失败...(image-6670c6-1580929245556)]

这个时候,按钮就在区域内了,可以点击按钮全部位置了

接下来就遇到第二个问题

2个box之间间隔一个区域,这个时候就不能选择这个区域了,2个box区域重叠,上面一个box的高度向下25,下面一个box的top向上25,中间的一个区域不能点击

设置区域position: 'absolute', zIndex: 100会导致按钮的3/4能点击,左下角1/4不能点击问题

[图片上传失败...(image-11774f-1580929245556)]

解决方案

 // 一块区域
     // 不定位
     // 定位(宽度80%)


解决之后

[图片上传失败...(image-7bd580-1580929245556)]

红色区域在andriod能点击选中

但是在ios中红色区域是在青色的内部(心中感到ios和anroid都有不同的渲染机制,都有坑),只有设置外层的View的zIndex: 100大于青色区域才行,ios中内部View的zIndex是在外层zIndex 的基础上的。所以方案失败。(如果设置外面的View的zIndex: 100,就不能设置width: 80%, 因为每个区域都有一个下边框,80%的话下边框的长度也变成了80%了,可以通过设置内部的View的width为Dimensions.get('window').width*0.8 这时候的下边框就是一样了,最终没采用这种方案)

最终方案

通过设置 scheduleList.map((li, index) => ()) 生成不同时间段的高为0.5的下边框(绝对定位), 内部View展示为80%,效果就是上图一样了

rn的体验等级,能用,凑合,流畅,丝滑

你可能感兴趣的:(react-native拖拽体验优化)