上一节我们已经简单的实现了侧滑删除,
我们最后还留了一个小小的功能,那就是当手指抬起的时候,我们需要选择打开或者关闭侧滑功能,我们分几种情况考虑:
大的条件分两种:
一、侧滑已经打开
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: