react-native-swipable-list-row
Version:
A simple and efficient react native swipable list row
203 lines (178 loc) • 4.8 kB
JavaScript
import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import {
View,
Animated,
PanResponder,
} from 'react-native';
export default class SwipableRowView extends PureComponent {
constructor(props) {
super(props);
this.width = new Animated.Value(0);
this.height = new Animated.Value(0);
this.translateX = new Animated.Value(0);
this.translateY = new Animated.Value(0);
this.X = new Animated.Value(0);
this.Y = new Animated.Value(0);
this.isClosing = false;
}
componentWillMount() {
this.panResponder = PanResponder.create({
onStartShouldSetPanResponder: () => true,
// onMoveShouldSetPanResponderCapture: () => true,
onPanResponderTerminationRequest: () => true,
onShouldBlockNativeResponder: () => false,
// can detect the distance here
onMoveShouldSetPanResponder: (e, gesture) => {
const dx = gesture.dx;
const dy = gesture.dy;
if (Math.abs(dy / dx) < 0.26 && (dx <= -10 || (this.X.__getValue() < 0 && dx >= 5))) {
// then this is a moving, so let scroll stop to avoid interfere
if (this.props.listView) {
this.props.listView.setNativeProps({ scrollEnabled: false });
}
return true;
}
return false;
},
// can stop touching at here
// onStartShouldSetPanResponderCapture: () => true,
onPanResponderGrant: () => {
if (this.isClosing) return;
this.X.setValue(this.X.__getValue() + this.translateX.__getValue());
this.translateX.setValue(0);
},
onPanResponderMove: Animated.event(
[null, { dx: this.translateX, dy: this.translateY }]),
onPanResponderRelease: () => {
if (this.props.listView) {
this.props.listView.setNativeProps({ scrollEnabled: true });
}
this.close();
},
onPanResponderTerminate: () => {
if (this.props.listView) {
this.props.listView.setNativeProps({ scrollEnabled: true });
}
this.close();
},
});
}
onLayout = () =>
Animated.event([
{
nativeEvent: {
layout: {
width: this.width,
height: this.height,
},
},
},
]);
close = () => {
const x = this.X.__getValue() + this.translateX.__getValue();
if (x < this.props.rightOffset) {
Animated.parallel([
Animated.timing(
this.X,
{
toValue: this.props.rightOffset,
duration: 100,
},
),
Animated.timing(
this.translateX,
{
toValue: 0,
duration: 100,
},
),
]).start();
}
if (x > this.props.rightOffset) {
Animated.parallel([
Animated.timing(
this.X,
{
toValue: 0,
duration: 100,
},
),
Animated.timing(
this.translateX,
{
toValue: 0,
duration: 100,
},
),
]).start();
}
}
closeRowOut = () => {
// const x = this.X.__getValue() + this.translateX.__getValue();
this.isClosing = true;
this.X.setValue(0);
this.translateX.setValue(0);
this.forceUpdate();
this.isClosing = false;
}
renderVisibleRow = () => {
if (typeof this.props.renderVisibleRow === 'function') {
return this.props.renderVisibleRow(this.closeRowOut);
}
return null;
}
renderHiddenRow = () => {
if (typeof this.props.renderHiddenRow === 'function') {
return this.props.renderHiddenRow();
}
return null;
}
render() {
return (
<View
{...this.panResponder.panHandlers}
>
<Animated.View
style={{
position: 'absolute',
left: 0,
width: this.width,
height: this.height,
}}
>
{this.renderHiddenRow()}
</Animated.View>
<Animated.View
onLayout={this.onLayout()}
style={{
flex: 1,
transform: [
{
translateX: Animated.add(this.X, this.translateX),
},
],
}}
>
{
this.renderVisibleRow()
}
</Animated.View>
</View>
);
}
}
const propTypes = {
rightOffset: PropTypes.number.isRequired,
renderVisibleRow: PropTypes.func.isRequired,
renderHiddenRow: PropTypes.func.isRequired,
listView: PropTypes.any,
};
const defaultProps = {
rightOffset: -100,
renderVisibleRow: () => null,
renderHiddenRow: () => null,
listView: null,
};
SwipableRowView.propTypes = propTypes;
SwipableRowView.defaultProps = defaultProps;