React-Native带你一步一步实现侧滑删除(二)

本文详细介绍了如何使用React-Native实现侧滑删除功能,包括不同状态下的逻辑判断,并探讨了React-Native事件传递机制,特别是在滑动事件与FlatList手势冲突时的解决方案。同时,深入源码解析了setNativeProps方法的工作原理。
摘要由CSDN通过智能技术生成

上一节我们已经简单的实现了侧滑删除,
这里写图片描述

我们最后还留了一个小小的功能,那就是当手指抬起的时候,我们需要选择打开或者关闭侧滑功能,我们分几种情况考虑:

大的条件分两种:
一、侧滑已经打开
1、抬起手指的时候,如果偏移的距离>=删除按钮距离(打开)

1、抬起手指的时候,如果偏移的距离<删除按钮距离(关闭)

二、侧滑没有打开
1、抬起手指的时候,如果偏移的距离>=删除按钮距离*偏移量(打开)

1、抬起手指的时候,如果偏移的距离<删除按钮距离*偏移量(关闭)

有了逻辑之后我们的代码就很简单了:

 /**
     * 结束事件的时候回调
     * @param event
     * @param gestureState
     * @private
     */
    _handlePanResponderEnd(event: Object, gestureState: Object): void {
        if(this._isOpen){
            if (Math.abs(this.state.currentLeft._value) >= 100) {
                this._animateToOpenPosition();
            } else {
                this._animateToClosedPosition();
            }
        }else{
            if (Math.abs(this.state.currentLeft._value) >= 100 / 3) {
                this._animateToOpenPosition();
            } else {
                this._animateToClosedPosition();
            }
        }
        this._previousLeft = null;
    }

最后是SwipeRow.js的全部代码:

/**
 * @author YASIN
 * @version [React-Native Ocj V01, 2018/3/13]
 * @date 17/2/23
 * @description SwipeRow
 */
import React, {
    Component,
} from 'react';
import PropTypes from 'prop-types';
import {
    Animated,
    PanResponder,
    Platform,
    StyleSheet,
    TouchableOpacity,
    ViewPropTypes,
    View,
    Text
} from 'react-native';

export default class SwipeRow extends Component {
   
    // 构造
    constructor(props) {
        super(props);
        // 初始状态
        this._panResponder = PanResponder.create({
            onMoveShouldSetPanResponderCapture: this._handleMoveShouldSetPanResponderCapture.bind(this),
            onPanResponderGrant: this._handlePanResponderGrant.bind(this),
            onPanResponderMove: this._handlePanResponderMove.bind(this),
            onPanResponderRelease: this._handlePanResponderEnd.bind(this),
            onPanResponderTerminate: this._handlePanResponderEnd.bind(this),
            onShouldBlockNativeResponder: (event, gestureState) => false,//表示是否用 Native 平台的事件处理,默认是禁用的,全部使用 JS 中的事件处理,注意此函数目前只能在 Android 平台上使用
        });
        //上一次滑动最后的left偏移量
        this._previousLeft = 0;
        //left偏移动画
        this.state = {
            currentLeft: new Animated.Value(this._previousLeft),
        };
        this._isOpen = false;
    }

    render() {
        return (
            <View style={[styles.swipeContainer, this.props.style]}>
                <View style={styles.swipeActions}>
                    {
  this.props.children[0]}
                </View>
                {
  this.renderRowContent()}
            </View>
        );
    }

    renderRowContent() {
        return (
            <Animated.View
                {...this._panResponder.panHandlers}
                style={
  {
                    transform: [
                        {translateX: this.state.currentLeft}
                    ]
                }}
            >
                {
  this.props.children[1]}
            </Animated.View>
        );
    }

    /**
     * 是否需要成为move事件响应者,返回true直接走onPanResponderMove
     * @param event
     * @param gestureState
     * @returns {boolean}
     * @private
     */
    _handleMoveShouldSetPanResponderCapture(event: Object, gestureState: Object,): boolean {
        //当垂直滑动的距离<10 水平滑动的距离>10的时候才让捕获事件
        console.log('_handleMoveShouldSetPanResponderCapture');
        return Math.abs(gestureState.dy) < 10 && Math.abs(gestureState.dx) > 10;
    }

    /**
     * 表示申请成功,组件成为了事件处理响应者
     * @param event
     * @param gestureState
     * @private
     */
    _handlePanResponderGrant(event: Object, gestureState: Object): void {
        console.log('_handlePanResponderGrant');
    }

    /**
     * 处理滑动事件
     * @param event
     * @param gestureState
     * @private
     */
    _handlePanResponderMove(event: Object, gestureState: Object): void {
        if (this._previousLeft === null) {
            this._previousLeft = this.state.currentLeft._value
        }
        let nowLeft = this._previousLeft + gestureState.dx * 1;
        //右滑最大距离为0(边界值)
        nowLeft = Math.min(nowLeft, 0);
        this.state.currentLeft.setValue(
            nowLeft,
        );
    }

    /**
     * 结束事件的时候回调
     * @param event
     * @param gestureState
     * @private
     */
    _handlePanResponderEnd(event: Object, gestureState: Object): void {
        if(this._isOpen){
            if (Math.abs(this.state.currentLeft._value) >= 100) {
                this._animateToOpenPosition();
            } else {
                this._animateToClosedPosition();
            }
        }else{
            if (Math.abs(this.state.currentLeft._value) >= 100 / 3) {
                this._animateToOpenPosition();
            } else {
                this._animateToClosedPosition();
            }
        }
        this._previousLeft = null;
    }

    _shouldAnimateRemainder(gestureState: Object): boolean {
        /**
         * If user has swiped past a certain distance, animate the rest of the way
         * if they let go
         */
        return (
            Math.abs(gestureState.dx) > 100 / 3 ||
            gestureState.vx > 0.3
        );
    }

    _animateToOpenPosition(): void {
        this._isOpen = true;
        this._animateTo(-100);
    }

    _animateToClosedPosition(duration: number = 300): void {
        this._isOpen = false;
        this._animateTo(0, duration);
    }

    _animateTo(toValue, duration = 300, callback): void {
        Animated.spring(
            this.state.currentLeft,
            {
                toValue,
            }
        ).start((value) => {
        });
    }
}
const styles = StyleSheet.create({
    swipeContainer: {
        width: '100%',
    },
    swipeActions: {
        backgroundColor: 
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值