UNPKG

react-native-swipable-list-row

Version:
203 lines (178 loc) 4.8 kB
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;