如果将 <TouchableOpacity> 移到内部导致侧滑效果消失,可能是因为 children 内部的触摸事件抢占了 PanResponder 的触摸事件。为了确保 PanResponder 能正确地处理触摸事件,我们需要确保 PanResponder 能优先处理触摸事件。可以通过在 onStartShouldSetPanResponder 和 onMoveShouldSetPanResponder 中添加逻辑来处理。
试试下面的改进版本:
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.cloneElement 将 children 进行克隆,并添加一个空的 onPress 方法,以确保 children 中的触摸事件不会抢占 PanResponder 的事件处理。这样可以确保滑动手势优先于子组件的触摸事件处理。