RN swipeable item option 仿qq拖动动画实现

实现:通过监听panResponder水平滑动,获取滑动距离和滑动方向,修改绝对定位view的偏移量,监听手势结束通过Animated使动画继续滑动到指定位置,通过overflow将子控件多余部分隐藏避免满屏幕滑动。

代码:

使用:

return (
   <RightDragView optionWidth={Dimens.dp160} itemView={this.dragItemView()}
                  optionView={this.dragOptionView()}/>
);

传入item:

dragItemView() {
   return (
      <View style={{
         flexDirection: 'row',
         height: Dimens.dp66,
         width:PhoneInfo.phone_width-Dimens.dp24,
         padding: Dimens.dp3,
         alignItems: 'center',
         backgroundColor: '#F9F9F9',
         borderRadius: Dimens.dp8,
      }}>
         
      </View>

   );
}

传入option:

dragOptionView() {
   return (
      <View style={{flexDirection: 'row', width: Dimens.dp160}}>
         <View style={{
            backgroundColor: '#4c4c4c',
            height: Dimens.dp66,
            width: Dimens.dp60,
            justifyContent: 'center',
         }}>
            <Text style={styles.textWhite}>设为在用</Text>
         </View>
         <View style={{
            height: Dimens.dp66,
            width: Dimens.dp50,
            backgroundColor: '#F29B48',
            justifyContent: 'center',
         }}>
            <TouchableOpacity style={{
               height: Dimens.dp66,
               width: Dimens.dp50,
               backgroundColor: '#F29B48',
               justifyContent: 'center',
            }} onPress={() => this.toEditPage()}>

               <Text style={styles.textWhite} onPress={()=>this.toEditPage()}>编辑</Text>

            </TouchableOpacity>
         </View>

         <View style={{
            backgroundColor: '#F75855',
            height: Dimens.dp66,
            width: Dimens.dp50,
            justifyContent: 'center',
         }}>
            <Text style={styles.textWhite}>绑定</Text>
         </View>
      </View>
   );
}

控件:

/**
 * itemOption水平滑动控件
 */
export default class RightDragView extends Component {

   constructor(props) {
      super(props);

      this.optionWidth=props.optionWidth
      //绝对定位偏移量
      this.left = new Animated.Value(0);
      this.grantValue = 0;
      this.direction = 0;
      this.aStyle = false;
   }

   componentWillMount() {
      this.panResponder = PanResponder.create({
         onStartShouldSetPanResponder: () => {
            return true;
         },
         onPanResponderGrant: (event, gestureState) => {
            this.direction = 0;
            this.grantValue = gestureState.x0;
         },
         onPanResponderMove: Animated.event(
            [null, {}], {
               listener: (event, gestureState) => {
                  if ((!this.aStyle && (gestureState.moveX - this.grantValue) >= 0) || (this.aStyle && (gestureState.moveX - this.grantValue) <= 0)) {
                     //最左边不能向左滑动,最右边不能向右滑动
                     return;
                  }
                  if(gestureState.moveX - this.grantValue>this.optionWidth||gestureState.moveX - this.grantValue<-this.optionWidth){
                     //最大滑动区间
                     return;
                  }
                  if (this.aStyle) {
                     //向右滑动
                     this.left.setValue((gestureState.moveX - this.grantValue) - this.optionWidth);
                  } else {
                     //向左滑动
                     this.left.setValue(gestureState.moveX - this.grantValue);
                  }
                  //保存滑动方向正值向右负数向左
                  this.direction = gestureState.moveX - this.grantValue;
               },
            },
         ),
         onPanResponderRelease: () => {
            if (this.direction === 0) {
               return;
            }
            /**
             * 手势滑动结束判断item自动完成滑动
             * */
            if (this.aStyle) {
               this.viewAnimatedHidden();
            } else {
               this.viewAnimatedStart();
            }
         },
      });
   }

   viewAnimatedStart() {
      this.aStyle = true;
      Animated.timing(this.left, {
         toValue: -this.optionWidth,
         duration: 200,
         useNativeDriver:false
      }).start();
   }

   viewAnimatedHidden() {
      this.aStyle = false;
      Animated.timing(this.left, {
         toValue: 0,
         duration: 200,
         useNativeDriver:false
      }).start();
   }

   render() {
      return (
         <View style={{
            flexDirection: 'row',
            overflow: 'hidden',
            marginTop: Dimens.dp16,
            marginRight: Dimens.dp12,
         }}>

            <Animated.View style={{
               flexDirection: 'row',
               width: PhoneInfo.phone_width - Dimens.dp24+this.optionWidth,
               position: 'relative',
               marginLeft: Dimens.dp12,
               left: this.left,
            }}
                           {...this.panResponder.panHandlers}>
               {
                  /**
                   * 显示item内容
                   */
                  this.props.itemView
               }

               {
                  /**
                   * 显示滑动option
                   */
                  this.props.optionView
               }

            </Animated.View>
         </View>
      );
   }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值