最近写rn项目,有遇到类似购物车侧滑删除的功能,刚开始看到了antd里面的SwipeAction 滑动操作这个组件,适配单个侧滑使用效果,达不到预想的那种列表滑动下一个单元上一个合并的效果。然后百度了一方找到了react-native-swipe-list-view组件库,想操作一番。因项目的体制问题,我们不能随便下载插件,然后我去就官网看了下源码,复制粘贴吗,程序员必备技术,源码放到自己的项目中实现了一下,但是还是不够近仁义啊,不能直接使用啊,预期的效果还是不够,然而只能在基于改动它的源码了。如下:
SwipeRow 这个代码并没有实质性的改动
'use strict';
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import {
Dimensions,
Animated,
PanResponder,
StyleSheet,
TouchableOpacity,
ViewPropTypes,
View,
} from 'react-native';
const DEFAULT_PREVIEW_OPEN_DELAY = 700;
const PREVIEW_CLOSE_DELAY = 300;
const MAX_VELOCITY_CONTRIBUTION = 5;
const SCROLL_LOCK_MILLISECONDS = 300;
/**
* Row that is generally used in a SwipeListView.
* If you are rendering a SwipeRow explicitly you must pass the SwipeRow exactly two children.
* The first will be rendered behind the second.
* e.g.
<SwipeRow>
<View style={hiddenRowStyle} />
<View style={visibleRowStyle} />
</SwipeRow>
*/
class SwipeRow extends Component {
constructor(props) {
super(props);
this.isOpen = false;
this.previousTrackedTranslateX = 0;
this.currentTranslateX = 0;
this.previousTrackedDirection = null;
this.horizontalSwipeGestureBegan = false;
this.swipeInitialX = null;
this.parentScrollEnabled = true;
this.ranPreview = false;
this._ensureScrollEnabledTimer = null;
this.isForceClosing = false;
this.state = {
dimensionsSet: false,
hiddenHeight: this.props.disableHiddenLayoutCalculation ? '100%' : 0,
hiddenWidth: this.props.disableHiddenLayoutCalculation ? '100%' : 0,
};
this._translateX = new Animated.Value(0);
this._panResponder = PanResponder.create({
onMoveShouldSetPanResponder: (e, gs) =>
this.handleOnMoveShouldSetPanResponder(e, gs),
onPanResponderMove: (e, gs) => this.handlePanResponderMove(e, gs),
onPanResponderRelease: (e, gs) => this.handlePanResponderEnd(e, gs),
onPanResponderTerminate: (e, gs) => this.handlePanResponderEnd(e, gs),
onShouldBlockNativeResponder: () => false,
});
this._translateX.addListener(({ value }) => {
this.currentTranslateX = value;
if (this.props.onSwipeValueChange) {
let direction = this.previousTrackedDirection;
if (value !== this.previousTrackedTranslateX) {
direction = value > this.previousTrackedTranslateX ? 'right' : 'left';
}
this.props.onSwipeValueChange &&
this.props.onSwipeValueChange({
isOpen: this.isOpen,
direction,
value,
});
this.previousTrackedTranslateX = value;
this.previousTrackedDirection = direction;
}
});
if (
this.props.forceCloseToRightThreshold &&
this.props.forceCloseToRightThreshold > 0
) {
this._translateX.addListener(({ value }) => {
if (
!this.isForceClosing &&
Dimensions.get('window').width + value <
this.props.forceCloseToRightThreshold
) {
this.isForceClosing = true;
this.forceCloseRow('right');
if (this.props.onForceCloseToRight) {
this.props.onForceCloseToRight();
}
}
});
}
if (
this.props.forceCloseToLeftThreshold &&
this.props.forceCloseToRightThreshold > 0
) {
this._translateX.addListener(({ value }) => {
if (
!this.isForceClosing &&
Dimensions.get('window').width - value <
this.props.forceCloseToLeftThreshold
) {
this.isForceClosing = true;
this.forceCloseRow('left');
if (this.props.onForceCloseToLeft) {
this.props.onForceCloseToLeft();
}
}
});
}
}
componentWillUnmount() {
clearTimeout(this._ensureScrollEnabledTimer);
this._translateX.removeAllListeners();
}
shouldComponentUpdate(nextProps, nextState) {
if (
this.state.hiddenHeight !== nextState.hiddenHeight ||
this.state.hiddenWidth !== nextState.hiddenWidth ||
!this.props.shouldItemUpdate ||
(this.props.shouldItemUpdate &&
this.props.shouldItemUpdate(this.props.item, nextProps.item))
) {
return true;
}
return false;
}
getPreviewAnimation(toValue, delay) {
return Animated.timing(this._translateX, {
duration: this.props.previewDuration,
toValue,
delay,
useNativeDriver: this.props.useNativeDriver,
});
}
onContentLayout(e) {
this.setState({
dimensionsSet: !this.props.recalculateHiddenLayout,
...(!this.props.disableHiddenLayoutCalculation
? {
hiddenHeight: e.nativeEvent.layout.height,
hiddenWidth: e.nativeEvent.layout.width,
}
: {}),
});
if (this.props.preview && !this.ranPreview) {
this.ranPreview = true;
const previewOpenValue =
this.props.previewOpenValue || this.props.rightOpenValue * 0.5;
this.getPreviewAnimation(
previewOpenValue,
this.props.previewOpenDelay,
).start(() => {
this.getPreviewAnimation(0, PREVIEW_CLOSE_DELAY).start();
});
}
}
onRowPress() {
if (this.props.onRowPress) {
this.props.onRowPress();
} else {
if (this.props.closeOnRowPress) {
this.closeRow();
}
}
}
handleOnMoveShouldSetPanResponder(e, gs) {
const { dx } = gs;
return Math.abs(dx) > this.props.directionalDistanceChangeThreshold;
}
handlePanResponderMove(e, gestureState) {
/* If the view is force closing, then ignore Moves. Return */
if (this.isForceClosing) {
return;
}
/* Else, do normal job */
const { dx, dy } = gestureState;
const absDx = Math.abs(dx);
const absDy = Math.abs(dy);
// this check may not be necessary because we don't capture the move until we pass the threshold
// just being extra safe here
if (
absDx > this.props.directionalDistanceChangeThreshold ||
absDy > this.props.directionalDistanceChangeThreshold
) {
// we have enough to determine direction
if (absDy > absDx && !this.horizontalSwipeGestureBegan) {
// user is moving vertically, do nothing, listView will handle
return;
}
// user is moving horizontally
if (this.parentScrollEnabled) {
// disable scrolling on the listView parent
this.parentScrollEnabled = false;
this.props.setScrollEnabled && this.props.setScrollEnabled(false);
}
if (this.swipeInitialX === null) {
// set tranlateX value when user started swiping
this.swipeInitialX = this.currentTranslateX;
}
if (!this.horizontalSwipeGestureBegan) {
this.horizontalSwipeGestureBegan = true;
this.props.swipeGestureBegan && this.props.swipeGestureBegan();
}
let newDX = this.swipeInitialX + dx;
if (this.props.disableLeftSwipe && newDX < 0) {
newDX = 0;
}
if (this.props.disableRightSwipe && newDX > 0) {
newDX = 0;
}
if (this.props.stopLeftSwipe && newDX > this.props.stopLeftSwipe) {
newDX = this.props.stopLeftSwipe;
}
if (this.props.stopRightSwipe && newDX < this.props.stopRightSwipe) {
newDX = this.props.stopRightSwipe;
}
this._translateX.setValue(newDX);
}
}
ensureScrollEnabled = () => {
if (!this.parentScrollEnabled) {
this.parentScrollEnabled = true;
this.props.setScrollEnabled && this.props.setScrollEnabled(true);
}
};
handlePanResponderEnd(e, gestureState) {
/* PandEnd will reset the force-closing state when it's true. */
if (this.isForceClosing) {
this.isForceClosing = false;
}
// decide how much the velocity will affect the final position that the list item settles in.
const swipeToOpenVelocityContribution = this.props
.swipeToOpenVelocityContribution;
const possibleExtraPixels =
this.props.rightOpenValue * swipeToOpenVelocityContribution;
const clampedVelocity = Math.min(
gestureState.vx,
MAX_VELOCITY_CONTRIBUTION,
);
const projectedExtraPixels =
possibleExtraPixels * (clampedVelocity / MAX_VELOCITY_CONTRIBUTION);
// re-enable scrolling on listView parent
this._ensureScrollEnabledTimer = setTimeout(
this.ensureScrollEnabled,
SCROLL_LOCK_MILLISECONDS,
);
// finish up the animation
let toValue = 0;
if (this.currentTranslateX >= 0) {
// trying to swipe right
if (this.swipeInitialX < this.currentTranslateX) {
if (
this.currentTranslateX - projectedExtraPixels >
this.props.leftOpenValue * (this.props.swipeToOpenPercent / 100)
) {
// we're more than halfway
toValue = this.props.leftOpenValue;
}
} else {
if (
this.currentTranslateX - projectedExtraPixels >
this.props.leftOpenValue * (1 - this.props.swipeToClosePercent / 100)
) {
toValue = this.props.leftOpenValue;
}
}
} else {
// trying to swipe left
if (this.swipeInitialX > this.currentTranslateX) {
if (
this.currentTranslateX - projectedExtraPixels <
this.props.rightOpenValue * (this.props.swipeToOpenPercent / 100)
) {
// we're more than halfway
toValue = this.props.rightOpenValue;
}
} else {
if (
this.currentTranslateX - projectedExtraPixels <
this.props.rightOpenValue * (1 - this.props.swipeToClosePercent / 100)
) {
toValue = this.props.rightOpenValue;
}
}
}
this.manuallySwipeRow(toValue);
}
/*
* This method is called by SwipeListView
*/
closeRow() {
this.manuallySwipeRow(0);
}
/**
* Force close the row toward the end of the given direction.
* @param {String} direction The direction to force close.
*/
forceCloseRow(direction) {
this.manuallySwipeRow(0, () => {
if (direction === 'right' && this.props.onForceCloseToRightEnd) {
this.props.onForceCloseToRightEnd();
} else if (direction === 'left' && this.props.onForceCloseToLeftEnd) {
this.props.onForceCloseToLeftEnd();
}
});
}
closeRowWithoutAnimation() {
this._translateX.setValue(0);
this.ensureScrollEnabled();
this.isOpen = false;
this.props.onRowDidClose && this.props.onRowDidClose();
this.props.onRowClose && this.props.onRowClose();
this.swipeInitialX = null;
this.horizontalSwipeGestureBegan = false;
}
manuallySwipeRow(toValue, onAnimationEnd) {
Animated.spring(this._translateX, {
toValue,
friction: this.props.friction,
tension: this.props.tension,
useNativeDriver: this.props.useNativeDriver,
}).start(() => {
this.ensureScrollEnabled();
if (toValue === 0) {
this.isOpen = false;
this.props.onRowDidClose && this.props.onRowDidClose();
} else {
this.isOpen = true;
this.props.onRowDidOpen && this.props.onRowDidOpen(toValue);
}
if (onAnimationEnd) {
onAnimationEnd();
}
});
if (toValue === 0) {
this.props.onRowClose && this.props.onRowClose();
} else {
this.props.onRowOpen && this.props.onRowOpen(toValue);
}
// reset everything
this.swipeInitialX = null;
this.horizontalSwipeGestureBegan = false;
}
combinedOnPress = () => {
const onPress = this.props.children[1].props.onPress;
this.onRowPress();
onPress && onPress();
};
renderVisibleContent() {
if (!this.props.closeOnRowPress) {
return this.props.children[1];
}
// handle touchables
const onPress = this.props.children[1].props.onPress;
if (onPress) {
return React.cloneElement(this.props.children[1], {
...this.props.children[1].props,
onPress: this.combinedOnPress,
});
}
return (
<TouchableOpacity activeOpacity={1} onPress={this.combinedOnPress}>
{this.props.children[1]}
</TouchableOpacity>
);
}
renderRowContent() {
// We do this annoying if statement for performance.
// We don't want the onLayout func to run after it runs once.
if (this.state.dimensionsSet) {
return (
<Animated.View
manipulationModes={['translateX']}
{...this._panResponder.panHandlers}
style={{
zIndex: 2,
transform: [{ translateX: this._translateX }],
}}>
{this.renderVisibleContent()}
</Animated.View>
);
} else {
return (
<Animated.View
manipulationModes={['translateX']}
{...this._panResponder.panHandlers}
onLayout={e => this.onContentLayout(e)}
style={{
zIndex: 2,
transform: [{ translateX: this._translateX }],
}}>
{this.renderVisibleContent()}
</Animated.View>
);
}
}
render() {
return (
<View style={this.props.style ? this.props.style : styles.container}>
<View
style={[
styles.hidden,
{
height: this.state.hiddenHeight,
width: this.state.hiddenWidth,
},
]}>
{this.props.children[0]}
</View>
{this.renderRowContent()}
</View>
);
}
}
const styles = StyleSheet.create({
container: {
// As of RN 0.29 flex: 1 is causing all rows to be the same height
// flex: 1
},
hidden: {
zIndex: 1,
bottom: 0,
left: 0,
overflow: 'hidden',
position: 'absolute',
right: 0,
top: 0,
},
});
SwipeRow.propTypes = {
/**
* Used by the SwipeListView to close rows on scroll events.
* You shouldn't need to use this prop explicitly.
*/
setScrollEnabled: PropTypes.func,
/**
* Called when it has been detected that a row should be swiped open.
*/
swipeGestureBegan: PropTypes.func,
/**
* Called when a swipe row is animating open. Used by the SwipeListView
* to keep references to open rows.
*/
onRowOpen: PropTypes.func,
/**
* Called when a swipe row has animated open.
*/
onRowDidOpen: PropTypes.func,
/**
* TranslateX value for opening the row to the left (positive number)
*/
leftOpenValue: PropTypes.number,
/**
* TranslateX value for opening the row to the right (negative number)
*/
rightOpenValue: PropTypes.number,
/**
* TranslateX value for stop the row to the left (positive number)
*/
stopLeftSwipe: PropTypes.number,
/**
* TranslateX value for stop the row to the right (negative number)
*/
stopRightSwipe: PropTypes.number,
/**
* Friction for the open / close animation
*/
friction: PropTypes.number,
/**
* Tension for the open / close animation
*/
tension: PropTypes.number,
/**
* Should the row be closed when it is tapped
*/
closeOnRowPress: PropTypes.bool,
/**
* Disable ability to swipe the row left
*/
disableLeftSwipe: PropTypes.bool,
/**
* Disable ability to swipe the row right
*/
disableRightSwipe: PropTypes.bool,
/**
* Enable hidden row onLayout calculations to run always
*/
recalculateHiddenLayout: PropTypes.bool,
/**
* Disable hidden row onLayout calculations
*/
disableHiddenLayoutCalculation: PropTypes.bool,
/**
* Called when a swipe row is animating closed
*/
onRowClose: PropTypes.func,
/**
* Called when a swipe row has animated closed
*/
onRowDidClose: PropTypes.func,
/**
* Styles for the parent wrapper View of the SwipeRow
*/
style: ViewPropTypes.style,
/**
* Should the row do a slide out preview to show that it is swipeable
*/
preview: PropTypes.bool,
/**
* Duration of the slide out preview animation
*/
previewDuration: PropTypes.number,
/**
* TranslateX value for the slide out preview animation
* Default: 0.5 * props.rightOpenValue
*/
previewOpenValue: PropTypes.number,
/**
* The dx value used to detect when a user has begun a swipe gesture
*/
directionalDistanceChangeThreshold: PropTypes.number,
/**
* What % of the left/right openValue does the user need to swipe
* past to trigger the row opening.
*/
swipeToOpenPercent: PropTypes.number,
/**
* Describes how much the ending velocity of the gesture contributes to whether the swipe will result in the item being closed or open.
* A velocity factor of 0 means that the velocity will have no bearing on whether the swipe settles on a closed or open position
* and it'll just take into consideration the swipeToOpenPercent.
*/
swipeToOpenVelocityContribution: PropTypes.number,
/**
* What % of the left/right openValue does the user need to swipe
* past to trigger the row closing.
*/
swipeToClosePercent: PropTypes.number,
/**
* callback to determine whether component should update (currentItem, newItem)
*/
shouldItemUpdate: PropTypes.func,
/**
* Callback invoked any time the swipe value of the row is changed
*/
onSwipeValueChange: PropTypes.func,
/**
* TranslateX amount(not value!) threshold that triggers force-closing the row to the Left End (positive number)
*/
forceCloseToLeftThreshold: PropTypes.number,
/**
* TranslateX amount(not value!) threshold that triggers force-closing the row to the Right End (positive number)
*/
forceCloseToRightThreshold: PropTypes.number,
/**
* Callback invoked when row is force closing to the Left End
*/
onForceCloseToLeft: PropTypes.func,
/**
* Callback invoked when row is force closing to the Right End
*/
onForceCloseToRight: PropTypes.func,
/**
* Callback invoked when row has finished force closing to the Left End
*/
onForceCloseToLeftEnd: PropTypes.func,
/**
* Callback invoked when row has finished force closing to the Right End
*/
onForceCloseToRightEnd: PropTypes.func,
/**
* useNativeDriver: true for all animations where possible
*/
useNativeDriver: PropTypes.bool,
/**
* Children
*/
children: PropTypes.node.isRequired,
};
SwipeRow.defaultProps = {
leftOpenValue: 0,
rightOpenValue: 0,
closeOnRowPress: true,
disableLeftSwipe: false,
disableRightSwipe: false,
recalculateHiddenLayout: false,
disableHiddenLayoutCalculation: false,
preview: false,
previewDuration: 300,
previewOpenDelay: DEFAULT_PREVIEW_OPEN_DELAY,
directionalDistanceChangeThreshold: 2,
swipeToOpenPercent: 50,
swipeToOpenVelocityContribution: 0,
swipeToClosePercent: 50,
item: {},
useNativeDriver: true,
};
export default SwipeRow;
SwipeList 主要改动的是list这个库
'use strict';
import React from 'react';
import PropTypes from 'prop-types';
import { FlatList, SectionList, Platform, ViewPropTypes } from 'react-native';
import BottomHint from '@components/PareFlatList/BottomHint';
import SwipeRow from './SwipeRow';
/**
* ListView that renders SwipeRows.
*/
class SwipeList extends React.Component {
constructor(props) {
super(props);
this._rows = {};
this.openCellKey = null;
this.listViewProps = {};
if (Platform.OS === 'ios') {
// Keep track of scroll offset and layout changes on iOS to be able to handle
// https://github.com/jemise111/react-native-swipe-list-view/issues/109
this.yScrollOffset = 0;
this.layoutHeight = 0;
this.listViewProps = {
onLayout: e => this.onLayout(e),
onContentSizeChange: (w, h) => this.onContentSizeChange(w, h),
};
}
}
setScrollEnabled(enable) {
if (this.props.scrollEnabled === false) {
return;
}
// Due to multiple issues reported across different versions of RN
// We do this in the safest way possible...
if (this._listView && this._listView.setNativeProps) {
this._listView.setNativeProps({ scrollEnabled: enable });
} else if (this._listView && this._listView.getScrollResponder) {
const scrollResponder = this._listView.getScrollResponder();
scrollResponder.setNativeProps &&
scrollResponder.setNativeProps({ scrollEnabled: enable });
}
this.props.onScrollEnabled && this.props.onScrollEnabled(enable);
}
safeCloseOpenRow() {
const rowRef = this._rows[this.openCellKey];
if (rowRef && rowRef.closeRow) {
this._rows[this.openCellKey].closeRow();
}
}
rowSwipeGestureBegan(key) {
if (
this.props.closeOnRowBeginSwipe &&
this.openCellKey &&
this.openCellKey !== key
) {
this.safeCloseOpenRow();
}
if (this.props.swipeGestureBegan) {
this.props.swipeGestureBegan(key);
}
}
onRowOpen(key, toValue) {
if (
this.openCellKey &&
this.openCellKey !== key &&
this.props.closeOnRowOpen &&
!this.props.closeOnRowBeginSwipe
) {
this.safeCloseOpenRow();
}
this.openCellKey = key;
this.props.onRowOpen && this.props.onRowOpen(key, this._rows, toValue);
}
onRowPress() {
if (this.openCellKey) {
if (this.props.closeOnRowPress) {
this.safeCloseOpenRow();
this.openCellKey = null;
}
}
}
onScroll(e) {
if (Platform.OS === 'ios') {
this.yScrollOffset = e.nativeEvent.contentOffset.y;
}
if (this.openCellKey) {
if (this.props.closeOnScroll) {
this.safeCloseOpenRow();
this.openCellKey = null;
}
}
this.props.onScroll && this.props.onScroll(e);
}
onLayout(e) {
this.layoutHeight = e.nativeEvent.layout.height;
this.props.onLayout && this.props.onLayout(e);
}
// When deleting rows on iOS, the list may end up being over-scrolled,
// which will prevent swiping any of the remaining rows. This triggers a scrollToEnd
// when that happens, which will make sure the list is kept in bounds.
// See: https://github.com/jemise111/react-native-swipe-list-view/issues/109
onContentSizeChange(w, h) {
const height = h - this.layoutHeight;
if (this.yScrollOffset >= height && height > 0) {
if (this._listView instanceof FlatList) {
this._listView && this._listView.scrollToEnd();
}
}
this.props.onContentSizeChange && this.props.onContentSizeChange(w, h);
}
setRefs(ref) {
this._listView = ref;
this.props.listViewRef && this.props.listViewRef(ref);
}
// In most use cases this is no longer used. Only in the case we are passed renderListView={true}
// there may be legacy code that passes a this.props.renderRow func so we keep this for legacy purposes
renderRow(rowData, secId, rowId, rowMap) {
const key = `${secId}${rowId}`;
const Component = this.props.renderRow(rowData, secId, rowId, rowMap);
const HiddenComponent =
this.props.renderHiddenRow &&
this.props.renderHiddenRow(rowData, secId, rowId, rowMap);
const previewRowId =
this.props.dataSource &&
this.props.dataSource.getRowIDForFlatIndex(
this.props.previewRowIndex || 0,
);
const shouldPreviewRow =
(this.props.previewFirstRow || this.props.previewRowIndex) &&
rowId === previewRowId;
return this.renderCell(
Component,
HiddenComponent,
key,
rowData,
shouldPreviewRow,
);
}
renderItem(rowData, rowMap) {
const Component = this.props.renderItem(rowData, rowMap);
const HiddenComponent =
this.props.renderHiddenItem &&
this.props.renderHiddenItem(rowData, rowMap);
const { item, index } = rowData;
let { num } = item;
let key = Number(num);
console.log(key);
if (!key && this.props.keyExtractor) {
key = this.props.keyExtractor(item, index);
}
const shouldPreviewRow =
typeof key !== 'undefined' && this.props.previewRowKey === key;
return this.renderCell(
Component,
HiddenComponent,
key,
item,
shouldPreviewRow,
);
}
renderCell(VisibleComponent, HiddenComponent, key, item, shouldPreviewRow) {
if (!HiddenComponent) {
return React.cloneElement(VisibleComponent, {
...VisibleComponent.props,
ref: row => (this._rows[key] = row),
onRowOpen: toValue => this.onRowOpen(key, toValue),
onRowDidOpen: toValue =>
this.props.onRowDidOpen &&
this.props.onRowDidOpen(key, this._rows, toValue),
onRowClose: () =>
this.props.onRowClose && this.props.onRowClose(key, this._rows),
onRowDidClose: () =>
this.props.onRowDidClose && this.props.onRowDidClose(key, this._rows),
onRowPress: () => this.onRowPress(),
setScrollEnabled: enable => this.setScrollEnabled(enable),
swipeGestureBegan: () => this.rowSwipeGestureBegan(key),
});
} else {
return (
<SwipeRow
onSwipeValueChange={
this.props.onSwipeValueChange
? data =>
this.props.onSwipeValueChange({
...data,
key,
})
: null
}
ref={row => (this._rows[key] = row)}
swipeGestureBegan={() => this.rowSwipeGestureBegan(key)}
onRowOpen={toValue => this.onRowOpen(key, toValue)}
onRowDidOpen={toValue =>
this.props.onRowDidOpen &&
this.props.onRowDidOpen(key, this._rows, toValue)
}
onRowClose={() =>
this.props.onRowClose && this.props.onRowClose(key, this._rows)
}
onRowDidClose={() =>
this.props.onRowDidClose &&
this.props.onRowDidClose(key, this._rows)
}
onRowPress={() => this.onRowPress(key)}
shouldItemUpdate={
this.props.shouldItemUpdate
? (currentItem, newItem) =>
this.props.shouldItemUpdate(currentItem, newItem)
: null
}
setScrollEnabled={enable => this.setScrollEnabled(enable)}
leftOpenValue={item.leftOpenValue || this.props.leftOpenValue}
rightOpenValue={item.rightOpenValue || this.props.rightOpenValue}
closeOnRowPress={item.closeOnRowPress || this.props.closeOnRowPress}
disableLeftSwipe={
item.disableLeftSwipe || this.props.disableLeftSwipe
}
disableRightSwipe={
item.disableRightSwipe || this.props.disableRightSwipe
}
stopLeftSwipe={item.stopLeftSwipe || this.props.stopLeftSwipe}
stopRightSwipe={item.stopRightSwipe || this.props.stopRightSwipe}
recalculateHiddenLayout={this.props.recalculateHiddenLayout}
disableHiddenLayoutCalculation={
this.props.disableHiddenLayoutCalculation
}
style={this.props.swipeRowStyle}
preview={shouldPreviewRow}
previewDuration={this.props.previewDuration}
previewOpenDelay={this.props.previewOpenDelay}
previewOpenValue={this.props.previewOpenValue}
tension={this.props.tension}
friction={this.props.friction}
directionalDistanceChangeThreshold={
this.props.directionalDistanceChangeThreshold
}
swipeToOpenPercent={this.props.swipeToOpenPercent}
swipeToOpenVelocityContribution={
this.props.swipeToOpenVelocityContribution
}
swipeToClosePercent={this.props.swipeToClosePercent}
item={item} // used for should item update comparisons
useNativeDriver={this.props.useNativeDriver}>
{HiddenComponent}
{VisibleComponent}
</SwipeRow>
);
}
}
/**底部View */
_footerComponent() {
if (this.props.ListFooterComponent) {
// return ListFooterComponent();
console.log('22222');
} else {
return this.props.isHiddenFoot ? null : (
<BottomHint
showFoot={this.props.showFoot}
textValue={this.props.bottomLineText}
/>
);
}
}
render() {
const { useSectionList, renderListView, ...props } = this.props;
// console.log(this.props, '-------')
if (renderListView) {
// Ideally renderRow should be deprecated. We do this check for
// legacy purposes to not break certain renderListView cases
const useRenderRow = !!this.props.renderRow;
return renderListView(
props,
this.setRefs.bind(this),
this.onScroll.bind(this),
useRenderRow
? this.renderRow.bind(this, this._rows)
: this.renderItem.bind(this),
);
}
if (useSectionList) {
return (
<SectionList
{...props}
{...this.listViewProps}
ref={c => this.setRefs(c)}
onScroll={e => this.onScroll(e)}
renderItem={rowData => this.renderItem(rowData, this._rows)}
refreshControl={this.props.swipeRefreshControl || null}
renderSectionHeader={this.props.renderHeaderView || null}
stickySectionHeade
rsEnabled={this.props.stickyHeadersEnabled || false}
/>
);
}
return (
<FlatList
{...props}
{...this.listViewProps}
ref={c => this.setRefs(c)}
onEndReachedThreshold={0.2}
onScroll={e => this.onScroll(e)}
renderItem={rowData => this.renderItem(rowData, this._rows)}
refreshControl={this.props.swipeRefreshControl || null}
ListFooterComponent={this._footerComponent(this.props)}
/>
);
}
}
SwipeListView.propTypes = {
/**
* To render a custom ListView component, if you don't want to use ReactNative one.
* Note: This will call `renderRow`, not `renderItem`
*/
renderListView: PropTypes.func,
/**
* How to render a row in a FlatList. Should return a valid React Element.
*/
renderItem: PropTypes.func,
/**
* How to render a hidden row in a FlatList (renders behind the row). Should return a valid React Element.
* This is required unless renderItem is passing a SwipeRow.
*/
renderHiddenItem: PropTypes.func,
/**
* TranslateX value for opening the row to the left (positive number)
*/
leftOpenValue: PropTypes.number,
/**
* TranslateX value for opening the row to the right (negative number)
*/
rightOpenValue: PropTypes.number,
/**
* TranslateX value for stop the row to the left (positive number)
*/
stopLeftSwipe: PropTypes.number,
/**
* TranslateX value for stop the row to the right (negative number)
*/
stopRightSwipe: PropTypes.number,
/**
* Should open rows be closed when the listView begins scrolling
*/
closeOnScroll: PropTypes.bool,
/**
* Should open rows be closed when a row is pressed
*/
closeOnRowPress: PropTypes.bool,
/**
* Should open rows be closed when a row begins to swipe open
*/
closeOnRowBeginSwipe: PropTypes.bool,
/**
* Should open rows be closed when another row is opened
*/
closeOnRowOpen: PropTypes.bool,
/**
* Disable ability to swipe rows left
*/
disableLeftSwipe: PropTypes.bool,
/**
* Disable ability to swipe rows right
*/
disableRightSwipe: PropTypes.bool,
/**
* Enable hidden row onLayout calculations to run always.
*
* By default, hidden row size calculations are only done on the first onLayout event
* for performance reasons.
* Passing ```true```here will cause calculations to run on every onLayout event.
* You may want to do this if your rows' sizes can change.
* One case is a SwipeListView with rows of different heights and an options to delete rows.
*/
recalculateHiddenLayout: PropTypes.bool,
/**
* Disable hidden row onLayout calculations
*
* Instead, {width: '100%', height: '100%'} will be used.
* Improves performance by avoiding component updates, while still working with orientation changes.
*/
disableHiddenLayoutCalculation: PropTypes.bool,
/**
* Called when a swipe row is animating swipe
*/
swipeGestureBegan: PropTypes.func,
/**
* Called when a swipe row is animating open
*/
onRowOpen: PropTypes.func,
/**
* Called when a swipe row has animated open
*/
onRowDidOpen: PropTypes.func,
/**
* Called when a swipe row is animating closed
*/
onRowClose: PropTypes.func,
/**
* Called when a swipe row has animated closed
*/
onRowDidClose: PropTypes.func,
/**
* Called when scrolling on the SwipeListView has been enabled/disabled
*/
onScrollEnabled: PropTypes.func,
/**
* Styles for the parent wrapper View of the SwipeRow
*/
swipeRowStyle: ViewPropTypes.style,
/**
* Called when the FlatList ref is set and passes a ref to the FlatList
* e.g. listViewRef={ ref => this._swipeListViewRef = ref }
*/
listViewRef: PropTypes.func,
/**
* Should the row with this key do a slide out preview to show that the list is swipeable
*/
previewRowKey: PropTypes.string,
/**
* [DEPRECATED] Should the first SwipeRow do a slide out preview to show that the list is swipeable
*/
previewFirstRow: PropTypes.bool,
/**
* [DEPRECATED] Should the specified rowId do a slide out preview to show that the list is swipeable
* Note: This ID will be passed to this function to get the correct row index
* https://facebook.github.io/react-native/docs/listviewdatasource.html#getrowidforflatindex
*/
previewRowIndex: PropTypes.number,
/**
* Duration of the slide out preview animation (milliseconds)
*/
previewDuration: PropTypes.number,
/**
* Delay of the slide out preview animation (milliseconds) // default 700ms
*/
prewiewOpenDelay: PropTypes.number,
/**
* TranslateX value for the slide out preview animation
* Default: 0.5 * props.rightOpenValue
*/
previewOpenValue: PropTypes.number,
/**
* Friction for the open / close animation
*/
friction: PropTypes.number,
/**
* Tension for the open / close animation
*/
tension: PropTypes.number,
/**
* The dx value used to detect when a user has begun a swipe gesture
*/
directionalDistanceChangeThreshold: PropTypes.number,
/**
* What % of the left/right openValue does the user need to swipe
* past to trigger the row opening.
*/
swipeToOpenPercent: PropTypes.number,
/**
* Describes how much the ending velocity of the gesture affects whether the swipe will result in the item being closed or open.
* A velocity factor of 0 means that the velocity will have no bearing on whether the swipe settles on a closed or open position
* and it'll just take into consideration the swipeToOpenPercent.
*/
swipeToOpenVelocityContribution: PropTypes.number,
/**
* What % of the left/right openValue does the user need to swipe
* past to trigger the row closing.
*/
swipeToClosePercent: PropTypes.number,
/**
* callback to determine whether component should update (currentItem, newItem)
*/
shouldItemUpdate: PropTypes.func,
/**
* Callback invoked any time the swipe value of a SwipeRow is changed
*/
onSwipeValueChange: PropTypes.func,
/**
* useNativeDriver: true for all animations where possible
*/
useNativeDriver: PropTypes.bool,
/**
* 下拉组件
*/
swipeRefreshControl: PropTypes.element,
listHeaderView: PropTypes.func,
showFoot: PropTypes.number,
ListFooterComponent: PropTypes.element,
// renderHeaderView: PropTypes.func,
// stickyHeadersEnabled: PropTypes.bool
};
SwipeListView.defaultProps = {
leftOpenValue: 0,
rightOpenValue: 0,
closeOnRowBeginSwipe: false,
closeOnScroll: true,
closeOnRowPress: true,
closeOnRowOpen: true,
disableLeftSwipe: false,
disableRightSwipe: false,
recalculateHiddenLayout: false,
disableHiddenLayoutCalculation: false,
previewFirstRow: false,
directionalDistanceChangeThreshold: 2,
swipeToOpenPercent: 50,
swipeToOpenVelocityContribution: 0,
swipeToClosePercent: 50,
useNativeDriver: true,
showFoot: 0,
};
export default SwipeList;
使用方法
<SwipeListView
style={[styles.scrollView, { marginBottom: marginButtom }]}
data={landRelated.notesList}
renderItem={(data, index) => (
<Card
key={`land-${data.index}`}
data={data.item}
onPress={() => props.onPress(data.item, data.index, 1)}
checkoutFlag={checkoutFlag}
onHandleEdit={onLandPress.bind(this, data.item)}
/>
)}
renderHiddenItem={(data, rowMap) =>
checkoutFlag ? null : (
<View style={styles.hideBgView}>
<TouchableOpacity
style={[styles.standaloneRowBack]}
onPress={() => checkDelete(data.item, this)}>
<View style={styles.swipe_cont_text_view}>
<Text style={styles.swipe_cont_text}>删除</Text>
</View>
</TouchableOpacity>
</View>
)
}
rightOpenValue={-75}
disableRightSwipe={true}
disableLeftSwipe={checkoutFlag ? true : false}
refreshing={landRelated.refReshing}
onRefresh={onRefresh}
onEndReached={onEndReached}
showFoot={landRelated.showFoot}
/>
大概就是这样!!!!!
如果侵犯请告知,会立马删除!!!谢谢