ReactNative 实现侧滑删除列表

ReactNative实现左滑删除列表

背景:

需求中要开发一个可以侧滑删除的列表,发现ReactNative并未供这种组件。ReactNative本身其实封装了具有侧滑功能的FlatList在以下目录,但已经被弃用了,研究了一下没有搞懂

./node_modules/react-native/Libraries/Experimental/SwipeableRow/SwipeableFlatList

之后尝试寻找一些第三方库,一个比较好用的是react-native-swipe-list-view,可以实现组件左右滑动、控制滑动的距离、删除动画以及预置的动画演示,符合要求的话建议用这个
react-native-swipe-list-view GitHub地址
react-native-swipe-list-view

但发现这种滑动实际上是两个组件,一个组件放在下面固定,上面的组件滑动,把下面隐藏的内容露出了,并且不能控制最大滑动的距离,只能禁用一侧的滑动,如果滑动超过了下面隐藏组件的范围,就会露出空白,虽然手势释放会回到设置的openValue,但这两点不符合UI的要求,只能开始研究自己实现.

实现效果

SwipeFlatList实现效果

代码

GitHub地址

SwipeRow

  • 模仿react-native-swipe-list-view,实现一个可以滑动的SwipeRow,用PanResponder手势处理以及Animated库来实现滑动、删除的动画
  • 实际上就是一个超过屏幕宽度的view,将隐藏元素放在屏幕外的部分,因为需求只用到左滑,实现的比较简单,利用view的高度绑定AnimatedValue,当删除行时就让view的高度变为0,达到视觉上的删除效果
  • 行的高度和隐藏组件的宽带必须传入来实现动画,如果行高或隐藏内容的宽度是不确定的,无法使用该组件
  • 如果点击隐藏内容后需要删除该行,可以通过ref调用delete功能,并在delete回调中移除列表中的数据,若在动画前就删除数据,不会触发动画,因为列表重新渲染了(可以在Example中看到示例)
import React, {
    PureComponent } from 'react';
import {
   
  Animated,
  PanResponder,
  TouchableOpacity,
  ViewStyle,
  GestureResponderEvent,
  PanResponderGestureState,
} from 'react-native';
import {
    WINDOW_WIDTH } from '../util';

type Props = {
   
  rightContent?: JSX.Element; //右侧屏幕外组件
  rightContanierStyle?: ViewStyle;
  onRightPress?: () => void; //右侧组件点击事件,若要关闭/删除行,可通过ref调用closwRow/deleteRow方法
  rightContentWidth: number; //右侧组件宽度,即最大左滑距离
  lineHeight: number; //行高,用来设置删除行动画
  onTouchStart?: () => void; //当行响应触摸事件时触发,可用来处理其他SwipeRow
  directionalDistanceChangeThreshold?: number; //接管事件的横向滑动距离
  //setScrollEnabled: (isEnabled: boolean) => void;
};

type State = {
   };

export class SwipeRow extends PureComponent<Props, State> {
   
  lineHeigh: Animated.Value;

  directionalDistanceChangeThreshold: number;

  constructor(props: any) {
   
    super(props);

    this.rightContentWidth = this.props.rightContentWidth || 0;
    this.lineHeigh = new Animated.Value(this.props.lineHeight);
    this.directionalDistanceChangeThreshold =
      this.props.directionalDistanceChangeThreshold || 2;
  }

  closeRow = () => {
   
    this._startAnimated(0);
  };

  deleteRow = (callbackFn?: () => void) => {
   
    Animated.timing(this.lineHeigh, {
   
      toValue: 0,
      duration: 600,
      useNativeDriver: false,
    }).start(callbackFn);
  };

  // x偏移
  pan = new Animated.Value(0);

  rightContentWidth = 0;

  //滑动超过指定距离时接管事件
  _onMoveShouldSet = (
    e: GestureResponderEvent,
    gestureState: PanResponderGestureState,
  ) => {
   
    const {
    dx } = gestureState;
    return Math.abs(dx) > this.directionalDistanceChangeThreshold;
  };

  //接管事件后触发函数
  _onPanResponderGrant = () => {
   
    this.props.onTouchStart && this.props.onTouchStart();
  };

  //滑动
  _onPanResponderMove = (
    e: GestureResponderEvent,
    gestureState: PanResponderGestureState,
  ) => {
   
    const {
    dx, dy } = gestureState;
    const absDx = Math.abs(dx);
    const absDy = Math.abs(dy);

    if (
      absDx > this.directionalDistanceChangeThreshold ||
      absDy > this.directionalDistanceChangeThreshold
    ) {
   
      if (absDy > absDx) {
   
        return;
      } // moving vertically

      //左滑,直接关闭行
      if (dx > 0) {
   
        this._startAnimated(0);
      }
      //右滑,最大距离为隐藏内容宽度
      else {
   
        if (dx < -this.rightContentWidth) {
   
          this._startAnimated(-this.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值