ReactNative实现侧滑删除

560 阅读1分钟

如果将 <TouchableOpacity> 移到内部导致侧滑效果消失,可能是因为 children 内部的触摸事件抢占了 PanResponder 的触摸事件。为了确保 PanResponder 能正确地处理触摸事件,我们需要确保 PanResponder 能优先处理触摸事件。可以通过在 onStartShouldSetPanResponderonMoveShouldSetPanResponder 中添加逻辑来处理。

试试下面的改进版本:

import React, { Component } from 'react';
import { View, Text, StyleSheet, Animated, PanResponder, TouchableOpacity } from 'react-native';
import { scaleSize } from '../../../../lib/util/ScreenUtil';

export default class SwipeableItem extends Component {
    constructor(props) {
        super(props);
        this.pan = new Animated.ValueXY();
        this.panResponder = PanResponder.create({
            onStartShouldSetPanResponder: () => true,
            onMoveShouldSetPanResponder: (e, gestureState) => {
                return Math.abs(gestureState.dx) > 10;
            },
            onPanResponderMove: (e, gestureState) => {
                if (gestureState.dx < 0) {
                    Animated.event([null, { dx: this.pan.x }], { useNativeDriver: false })(e, gestureState);
                }
            },
            onPanResponderRelease: (e, gestureState) => {
                if (gestureState.dx < -100) {
                    Animated.timing(this.pan, {
                        toValue: { x: -150, y: 0 },
                        duration: 200,
                        useNativeDriver: false,
                    }).start();
                } else {
                    Animated.spring(this.pan, {
                        toValue: { x: 0, y: 0 },
                        useNativeDriver: false,
                    }).start();
                }
            },
        });
    }

    handleDeletePress = () => {
        this.props.onDelete(this.props.item.id);
    };

    handleEditPress = () => {
        this.props.onEdit(this.props.item.id);
    };

    render() {
        const { children } = this.props;
        return (
            <View style={styles.itemWrapper}>
                <View style={styles.hiddenButtons}>
                    <TouchableOpacity
                        onPress={this.handleEditPress}
                        style={[styles.button, styles.editButton]}>
                        <Text style={styles.buttonText}>修改</Text>
                    </TouchableOpacity>
                    <TouchableOpacity
                        onPress={this.handleDeletePress}
                        style={[styles.button, styles.deleteButton]}>
                        <Text style={styles.buttonText}>删除</Text>
                    </TouchableOpacity>
                </View>
                <Animated.View
                    style={[styles.itemContainer, { transform: this.pan.getTranslateTransform() }]}
                    {...this.panResponder.panHandlers}>
                    {React.cloneElement(children, { onPress: () => {} })}
                </Animated.View>
            </View>
        );
    }
}

const styles = StyleSheet.create({
    container: {
        flex: 1,
        backgroundColor: '#fff',
    },
    itemWrapper: {
        flexDirection: 'row',
        alignItems: 'center',
        paddingVertical: scaleSize(5),
    },
    hiddenButtons: {
        flexDirection: 'row',
        position: 'absolute',
        right: 0,
        height: '100%',
        justifyContent: 'center',
        alignItems: 'center',
        backgroundColor: '#f9f9f9',
    },
    button: {
        width: 75,
        height: '100%',
        justifyContent: 'center',
        alignItems: 'center',
    },
    editButton: {
        backgroundColor: 'blue',
        height: '100%',
    },
    deleteButton: {
        backgroundColor: 'red',
    },
    buttonText: {
        color: '#fff',
        fontWeight: 'bold',
    },
    itemContainer: {
        width: '100%',
    },
    itemText: {
        fontSize: 18,
    },
});

在这个版本中,我添加了 onMoveShouldSetPanResponder 方法来确保只有在横向滑动超过 10 像素时才启动滑动手势,这样可以防止纵向滚动和点击事件对滑动手势的干扰。

同时使用 React.cloneElementchildren 进行克隆,并添加一个空的 onPress 方法,以确保 children 中的触摸事件不会抢占 PanResponder 的事件处理。这样可以确保滑动手势优先于子组件的触摸事件处理。