690 lines
20 KiB
JavaScript
690 lines
20 KiB
JavaScript
import React, {Component} from 'react';
|
||
import PropTypes from 'prop-types';
|
||
import {ScrollView, View, StyleSheet, Platform, RefreshControl, ViewPropTypes} from 'react-native';
|
||
import {shallowEqual, swapArrayElements} from './utils';
|
||
import Row from './Row';
|
||
|
||
const AUTOSCROLL_INTERVAL = 100;
|
||
const ZINDEX = Platform.OS === 'ios' ? 'zIndex' : 'elevation';
|
||
|
||
function uniqueRowKey(key) {
|
||
return `${key}${uniqueRowKey.id}`
|
||
}
|
||
|
||
uniqueRowKey.id = 0
|
||
|
||
export default class SortableList extends Component {
|
||
static propTypes = {
|
||
data: PropTypes.oneOfType([PropTypes.array, PropTypes.object]).isRequired,
|
||
order: PropTypes.arrayOf(PropTypes.any),
|
||
style: ViewPropTypes.style,
|
||
contentContainerStyle: ViewPropTypes.style,
|
||
innerContainerStyle: ViewPropTypes.style,
|
||
sortingEnabled: PropTypes.bool,
|
||
scrollEnabled: PropTypes.bool,
|
||
horizontal: PropTypes.bool,
|
||
showsVerticalScrollIndicator: PropTypes.bool,
|
||
showsHorizontalScrollIndicator: PropTypes.bool,
|
||
refreshControl: PropTypes.element,
|
||
autoscrollAreaSize: PropTypes.number,
|
||
snapToAlignment: PropTypes.string,
|
||
rowActivationTime: PropTypes.number,
|
||
manuallyActivateRows: PropTypes.bool,
|
||
keyboardShouldPersistTaps: PropTypes.oneOf(['never', 'always', 'handled']),
|
||
scrollEventThrottle: PropTypes.number,
|
||
decelerationRate: PropTypes.oneOf([PropTypes.string, PropTypes.number]),
|
||
pagingEnabled: PropTypes.bool,
|
||
nestedScrollEnabled: PropTypes.bool,
|
||
disableIntervalMomentum: PropTypes.bool,
|
||
|
||
renderRow: PropTypes.func.isRequired,
|
||
renderHeader: PropTypes.func,
|
||
renderFooter: PropTypes.func,
|
||
|
||
onChangeOrder: PropTypes.func,
|
||
onActivateRow: PropTypes.func,
|
||
onReleaseRow: PropTypes.func,
|
||
onScroll: PropTypes.func,
|
||
};
|
||
|
||
static defaultProps = {
|
||
sortingEnabled: true,
|
||
scrollEnabled: true,
|
||
keyboardShouldPersistTaps: 'never',
|
||
autoscrollAreaSize: 60,
|
||
snapToAlignment: 'start',
|
||
manuallyActivateRows: false,
|
||
showsVerticalScrollIndicator: true,
|
||
showsHorizontalScrollIndicator: true,
|
||
scrollEventThrottle: 2,
|
||
decelerationRate: 'normal',
|
||
pagingEnabled: false,
|
||
onScroll: () => {}
|
||
}
|
||
|
||
/**
|
||
* Stores refs to rows’ components by keys.
|
||
*/
|
||
_rows = {};
|
||
|
||
/**
|
||
* Stores promises of rows’ layouts.
|
||
*/
|
||
_rowsLayouts = {};
|
||
_resolveRowLayout = {};
|
||
|
||
_contentOffset = {x: 0, y: 0};
|
||
|
||
state = {
|
||
animated: false,
|
||
order: this.props.order || Object.keys(this.props.data),
|
||
rowsLayouts: null,
|
||
containerLayout: null,
|
||
data: this.props.data,
|
||
activeRowKey: null,
|
||
activeRowIndex: null,
|
||
releasedRowKey: null,
|
||
sortingEnabled: this.props.sortingEnabled,
|
||
scrollEnabled: this.props.scrollEnabled
|
||
};
|
||
|
||
componentWillMount() {
|
||
this.state.order.forEach((key) => {
|
||
this._rowsLayouts[key] = new Promise((resolve) => {
|
||
this._resolveRowLayout[key] = resolve;
|
||
});
|
||
});
|
||
|
||
if (this.props.renderHeader && !this.props.horizontal) {
|
||
this._headerLayout = new Promise((resolve) => {
|
||
this._resolveHeaderLayout = resolve;
|
||
});
|
||
}
|
||
if (this.props.renderFooter && !this.props.horizontal) {
|
||
this._footerLayout = new Promise((resolve) => {
|
||
this._resolveFooterLayout = resolve;
|
||
});
|
||
}
|
||
}
|
||
|
||
componentDidMount() {
|
||
this._onUpdateLayouts();
|
||
}
|
||
|
||
componentWillReceiveProps(nextProps) {
|
||
const {data, order} = this.state;
|
||
let {data: nextData, order: nextOrder} = nextProps;
|
||
|
||
if (data && nextData && !shallowEqual(data, nextData)) {
|
||
nextOrder = nextOrder || Object.keys(nextData)
|
||
uniqueRowKey.id++;
|
||
this._rowsLayouts = {};
|
||
nextOrder.forEach((key) => {
|
||
this._rowsLayouts[key] = new Promise((resolve) => {
|
||
this._resolveRowLayout[key] = resolve;
|
||
});
|
||
});
|
||
|
||
if (Object.keys(nextData).length > Object.keys(data).length) {
|
||
this.setState({
|
||
animated: false,
|
||
data: nextData,
|
||
containerLayout: null,
|
||
rowsLayouts: null,
|
||
order: nextOrder
|
||
});
|
||
} else {
|
||
this.setState({
|
||
data: nextData,
|
||
order: nextOrder
|
||
});
|
||
}
|
||
|
||
} else if (order && nextOrder && !shallowEqual(order, nextOrder)) {
|
||
this.setState({order: nextOrder});
|
||
}
|
||
}
|
||
|
||
componentDidUpdate(prevProps, prevState) {
|
||
const {data, scrollEnabled} = this.state;
|
||
const {data: prevData} = prevState;
|
||
|
||
if (data && prevData && !shallowEqual(data, prevData)) {
|
||
this._onUpdateLayouts();
|
||
}
|
||
if (prevProps.scrollEnabled !== scrollEnabled) {
|
||
this.setState({scrollEnabled: prevProps.scrollEnabled})
|
||
}
|
||
}
|
||
|
||
scrollBy({dx = 0, dy = 0, animated = false}) {
|
||
if (this.props.horizontal) {
|
||
this._contentOffset.x += dx;
|
||
} else {
|
||
this._contentOffset.y += dy;
|
||
}
|
||
|
||
this._scroll(animated);
|
||
}
|
||
|
||
scrollTo({x = 0, y = 0, animated = false}) {
|
||
if (this.props.horizontal) {
|
||
this._contentOffset.x = x;
|
||
} else {
|
||
this._contentOffset.y = y;
|
||
}
|
||
|
||
this._scroll(animated);
|
||
}
|
||
|
||
scrollToRowKey({key, animated = false}) {
|
||
const {order, containerLayout, rowsLayouts} = this.state;
|
||
|
||
let keyX = 0;
|
||
let keyY = 0;
|
||
|
||
for (const rowKey of order) {
|
||
if (rowKey === key) {
|
||
break;
|
||
}
|
||
|
||
keyX += rowsLayouts[rowKey].width;
|
||
keyY += rowsLayouts[rowKey].height;
|
||
}
|
||
|
||
// Scroll if the row is not visible.
|
||
if (
|
||
this.props.horizontal
|
||
? (keyX < this._contentOffset.x || keyX > this._contentOffset.x + containerLayout.width)
|
||
: (keyY < this._contentOffset.y || keyY > this._contentOffset.y + containerLayout.height)
|
||
) {
|
||
if (this.props.horizontal) {
|
||
this._contentOffset.x = keyX;
|
||
} else {
|
||
this._contentOffset.y = keyY;
|
||
}
|
||
|
||
this._scroll(animated);
|
||
}
|
||
}
|
||
|
||
render() {
|
||
let {
|
||
contentContainerStyle,
|
||
innerContainerStyle,
|
||
horizontal,
|
||
style,
|
||
showsVerticalScrollIndicator,
|
||
showsHorizontalScrollIndicator,
|
||
snapToAlignment,
|
||
scrollEventThrottle,
|
||
decelerationRate,
|
||
pagingEnabled,
|
||
nestedScrollEnabled,
|
||
disableIntervalMomentum,
|
||
keyboardShouldPersistTaps,
|
||
} = this.props;
|
||
const {animated, contentHeight, contentWidth, scrollEnabled} = this.state;
|
||
const containerStyle = StyleSheet.flatten([style, {opacity: Number(animated)}])
|
||
innerContainerStyle = [
|
||
styles.rowsContainer,
|
||
horizontal ? {width: contentWidth} : {height: contentHeight},
|
||
innerContainerStyle
|
||
];
|
||
let {refreshControl} = this.props;
|
||
|
||
if (refreshControl && refreshControl.type === RefreshControl) {
|
||
refreshControl = React.cloneElement(this.props.refreshControl, {
|
||
enabled: scrollEnabled, // fix for Android
|
||
});
|
||
}
|
||
|
||
return (
|
||
<View style={containerStyle} ref={this._onRefContainer}>
|
||
<ScrollView
|
||
nestedScrollEnabled={nestedScrollEnabled}
|
||
disableIntervalMomentum={disableIntervalMomentum}
|
||
refreshControl={refreshControl}
|
||
ref={this._onRefScrollView}
|
||
horizontal={horizontal}
|
||
contentContainerStyle={contentContainerStyle}
|
||
scrollEventThrottle={scrollEventThrottle}
|
||
pagingEnabled={pagingEnabled}
|
||
decelerationRate={decelerationRate}
|
||
scrollEnabled={scrollEnabled}
|
||
keyboardShouldPersistTaps={keyboardShouldPersistTaps}
|
||
showsHorizontalScrollIndicator={showsHorizontalScrollIndicator}
|
||
showsVerticalScrollIndicator={showsVerticalScrollIndicator}
|
||
snapToAlignment={snapToAlignment}
|
||
onScroll={this._onScroll}
|
||
>
|
||
{this._renderHeader()}
|
||
<View style={innerContainerStyle}>
|
||
{this._renderRows()}
|
||
</View>
|
||
{this._renderFooter()}
|
||
</ScrollView>
|
||
</View>
|
||
);
|
||
}
|
||
|
||
_renderRows() {
|
||
const {horizontal, rowActivationTime, sortingEnabled, renderRow} = this.props;
|
||
const {animated, order, data, activeRowKey, releasedRowKey, rowsLayouts} = this.state;
|
||
|
||
|
||
let nextX = 0;
|
||
let nextY = 0;
|
||
|
||
return order.map((key, index) => {
|
||
const style = {[ZINDEX]: 0};
|
||
const location = {x: 0, y: 0};
|
||
|
||
if (rowsLayouts) {
|
||
if (horizontal) {
|
||
location.x = nextX;
|
||
nextX += rowsLayouts[key] ? rowsLayouts[key].width : 0;
|
||
} else {
|
||
location.y = nextY;
|
||
nextY += rowsLayouts[key] ? rowsLayouts[key].height : 0;
|
||
}
|
||
}
|
||
|
||
const active = activeRowKey === key;
|
||
const released = releasedRowKey === key;
|
||
|
||
if (active || released) {
|
||
style[ZINDEX] = 100;
|
||
}
|
||
|
||
return (
|
||
<Row
|
||
key={uniqueRowKey(key)}
|
||
ref={this._onRefRow.bind(this, key)}
|
||
horizontal={horizontal}
|
||
activationTime={rowActivationTime}
|
||
animated={animated && !active}
|
||
disabled={!sortingEnabled}
|
||
style={style}
|
||
location={location}
|
||
onLayout={!rowsLayouts ? this._onLayoutRow.bind(this, key) : null}
|
||
onActivate={this._onActivateRow.bind(this, key, index)}
|
||
onPress={this._onPressRow.bind(this, key)}
|
||
onRelease={this._onReleaseRow.bind(this, key)}
|
||
onMove={this._onMoveRow}
|
||
manuallyActivateRows={this.props.manuallyActivateRows}>
|
||
{renderRow({
|
||
key,
|
||
data: data[key],
|
||
disabled: !sortingEnabled,
|
||
active,
|
||
index,
|
||
})}
|
||
</Row>
|
||
);
|
||
});
|
||
}
|
||
|
||
_renderHeader() {
|
||
if (!this.props.renderHeader || this.props.horizontal) {
|
||
return null;
|
||
}
|
||
|
||
const {headerLayout} = this.state;
|
||
|
||
return (
|
||
<View onLayout={!headerLayout ? this._onLayoutHeader : null}>
|
||
{this.props.renderHeader()}
|
||
</View>
|
||
);
|
||
}
|
||
|
||
_renderFooter() {
|
||
if (!this.props.renderFooter || this.props.horizontal) {
|
||
return null;
|
||
}
|
||
|
||
const {footerLayout} = this.state;
|
||
|
||
return (
|
||
<View onLayout={!footerLayout ? this._onLayoutFooter : null}>
|
||
{this.props.renderFooter()}
|
||
</View>
|
||
);
|
||
}
|
||
|
||
_onUpdateLayouts() {
|
||
Promise.all([this._headerLayout, this._footerLayout, ...Object.values(this._rowsLayouts)])
|
||
.then(([headerLayout, footerLayout, ...rowsLayouts]) => {
|
||
// Can get correct container’s layout only after rows’s layouts.
|
||
this._container.measure((x, y, width, height, pageX, pageY) => {
|
||
const rowsLayoutsByKey = {};
|
||
let contentHeight = 0;
|
||
let contentWidth = 0;
|
||
|
||
rowsLayouts.forEach(({rowKey, layout}) => {
|
||
rowsLayoutsByKey[rowKey] = layout;
|
||
contentHeight += layout.height;
|
||
contentWidth += layout.width;
|
||
});
|
||
|
||
this.setState({
|
||
containerLayout: {x, y, width, height, pageX, pageY},
|
||
rowsLayouts: rowsLayoutsByKey,
|
||
headerLayout,
|
||
footerLayout,
|
||
contentHeight,
|
||
contentWidth,
|
||
}, () => {
|
||
this.setState({animated: true});
|
||
});
|
||
});
|
||
});
|
||
}
|
||
|
||
_scroll(animated) {
|
||
this._scrollView.scrollTo({...this._contentOffset, animated});
|
||
}
|
||
|
||
/**
|
||
* Finds a row under the moving row, if they are neighbours,
|
||
* swaps them, else shifts rows.
|
||
*/
|
||
_setOrderOnMove() {
|
||
const {activeRowKey, activeRowIndex, order} = this.state;
|
||
|
||
if (activeRowKey === null || this._autoScrollInterval) {
|
||
return;
|
||
}
|
||
|
||
let {
|
||
rowKey: rowUnderActiveKey,
|
||
rowIndex: rowUnderActiveIndex,
|
||
} = this._findRowUnderActiveRow();
|
||
|
||
if (this._movingDirectionChanged) {
|
||
this._prevSwapedRowKey = null;
|
||
}
|
||
|
||
// Swap rows if necessary.
|
||
if (rowUnderActiveKey !== activeRowKey && rowUnderActiveKey !== this._prevSwapedRowKey) {
|
||
const isNeighbours = Math.abs(rowUnderActiveIndex - activeRowIndex) === 1;
|
||
let nextOrder;
|
||
|
||
// If they are neighbours, swap elements, else shift.
|
||
if (isNeighbours) {
|
||
this._prevSwapedRowKey = rowUnderActiveKey;
|
||
nextOrder = swapArrayElements(order, activeRowIndex, rowUnderActiveIndex);
|
||
} else {
|
||
nextOrder = order.slice();
|
||
nextOrder.splice(activeRowIndex, 1);
|
||
nextOrder.splice(rowUnderActiveIndex, 0, activeRowKey);
|
||
}
|
||
|
||
this.setState({
|
||
order: nextOrder,
|
||
activeRowIndex: rowUnderActiveIndex,
|
||
}, () => {
|
||
if (this.props.onChangeOrder) {
|
||
this.props.onChangeOrder(nextOrder);
|
||
}
|
||
});
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Finds a row, which was covered with the moving row’s half.
|
||
*/
|
||
_findRowUnderActiveRow() {
|
||
const {horizontal} = this.props;
|
||
const {rowsLayouts, activeRowKey, activeRowIndex, order} = this.state;
|
||
const movingRowLayout = rowsLayouts[activeRowKey];
|
||
const rowLeftX = this._activeRowLocation.x
|
||
const rowRightX = rowLeftX + movingRowLayout.width;
|
||
const rowTopY = this._activeRowLocation.y;
|
||
const rowBottomY = rowTopY + movingRowLayout.height;
|
||
|
||
for (
|
||
let currentRowIndex = 0, x = 0, y = 0, rowsCount = order.length;
|
||
currentRowIndex < rowsCount - 1;
|
||
currentRowIndex++
|
||
) {
|
||
const currentRowKey = order[currentRowIndex];
|
||
const currentRowLayout = rowsLayouts[currentRowKey];
|
||
const nextRowIndex = currentRowIndex + 1;
|
||
const nextRowLayout = rowsLayouts[order[nextRowIndex]];
|
||
|
||
x += currentRowLayout.width;
|
||
y += currentRowLayout.height;
|
||
|
||
if (currentRowKey !== activeRowKey && (
|
||
horizontal
|
||
? ((x - currentRowLayout.width <= rowLeftX || currentRowIndex === 0) && rowLeftX <= x - currentRowLayout.width / 3)
|
||
: ((y - currentRowLayout.height <= rowTopY || currentRowIndex === 0) && rowTopY <= y - currentRowLayout.height / 3)
|
||
)) {
|
||
return {
|
||
rowKey: order[currentRowIndex],
|
||
rowIndex: currentRowIndex,
|
||
};
|
||
}
|
||
|
||
if (horizontal
|
||
? (x + nextRowLayout.width / 3 <= rowRightX && (rowRightX <= x + nextRowLayout.width || nextRowIndex === rowsCount - 1))
|
||
: (y + nextRowLayout.height / 3 <= rowBottomY && (rowBottomY <= y + nextRowLayout.height || nextRowIndex === rowsCount - 1))
|
||
) {
|
||
return {
|
||
rowKey: order[nextRowIndex],
|
||
rowIndex: nextRowIndex,
|
||
};
|
||
}
|
||
}
|
||
|
||
return {rowKey: activeRowKey, rowIndex: activeRowIndex};
|
||
}
|
||
|
||
_scrollOnMove(e) {
|
||
const {pageX, pageY} = e.nativeEvent;
|
||
const {horizontal} = this.props;
|
||
const {containerLayout} = this.state;
|
||
let inAutoScrollBeginArea = false;
|
||
let inAutoScrollEndArea = false;
|
||
|
||
if (horizontal) {
|
||
inAutoScrollBeginArea = pageX < containerLayout.pageX + this.props.autoscrollAreaSize;
|
||
inAutoScrollEndArea = pageX > containerLayout.pageX + containerLayout.width - this.props.autoscrollAreaSize;
|
||
} else {
|
||
inAutoScrollBeginArea = pageY < containerLayout.pageY + this.props.autoscrollAreaSize;
|
||
inAutoScrollEndArea = pageY > containerLayout.pageY + containerLayout.height - this.props.autoscrollAreaSize;
|
||
}
|
||
|
||
if (!inAutoScrollBeginArea &&
|
||
!inAutoScrollEndArea &&
|
||
this._autoScrollInterval !== null
|
||
) {
|
||
this._stopAutoScroll();
|
||
}
|
||
|
||
// It should scroll and scrolling is processing.
|
||
if (this._autoScrollInterval !== null) {
|
||
return;
|
||
}
|
||
|
||
if (inAutoScrollBeginArea) {
|
||
this._startAutoScroll({
|
||
direction: -1,
|
||
shouldScroll: () => this._contentOffset[horizontal ? 'x' : 'y'] > 0,
|
||
getScrollStep: (stepIndex) => {
|
||
const nextStep = this._getScrollStep(stepIndex);
|
||
const contentOffset = this._contentOffset[horizontal ? 'x' : 'y'];
|
||
|
||
return contentOffset - nextStep < 0 ? contentOffset : nextStep;
|
||
},
|
||
});
|
||
} else if (inAutoScrollEndArea) {
|
||
this._startAutoScroll({
|
||
direction: 1,
|
||
shouldScroll: () => {
|
||
const {
|
||
contentHeight,
|
||
contentWidth,
|
||
containerLayout,
|
||
footerLayout = {height: 0},
|
||
} = this.state;
|
||
|
||
if (horizontal) {
|
||
return this._contentOffset.x < contentWidth - containerLayout.width
|
||
} else {
|
||
return this._contentOffset.y < contentHeight + footerLayout.height - containerLayout.height;
|
||
}
|
||
},
|
||
getScrollStep: (stepIndex) => {
|
||
const nextStep = this._getScrollStep(stepIndex);
|
||
const {
|
||
contentHeight,
|
||
contentWidth,
|
||
containerLayout,
|
||
footerLayout = {height: 0},
|
||
} = this.state;
|
||
|
||
if (horizontal) {
|
||
return this._contentOffset.x + nextStep > contentWidth - containerLayout.width
|
||
? contentWidth - containerLayout.width - this._contentOffset.x
|
||
: nextStep;
|
||
} else {
|
||
const scrollHeight = contentHeight + footerLayout.height - containerLayout.height;
|
||
|
||
return this._contentOffset.y + nextStep > scrollHeight
|
||
? scrollHeight - this._contentOffset.y
|
||
: nextStep;
|
||
}
|
||
},
|
||
});
|
||
}
|
||
}
|
||
|
||
_getScrollStep(stepIndex) {
|
||
return stepIndex > 3 ? 60 : 30;
|
||
}
|
||
|
||
_startAutoScroll({direction, shouldScroll, getScrollStep}) {
|
||
if (!shouldScroll()) {
|
||
return;
|
||
}
|
||
|
||
const {activeRowKey} = this.state;
|
||
const {horizontal} = this.props;
|
||
let counter = 0;
|
||
|
||
this._autoScrollInterval = setInterval(() => {
|
||
if (shouldScroll()) {
|
||
const movement = {
|
||
[horizontal ? 'dx' : 'dy']: direction * getScrollStep(counter++),
|
||
};
|
||
|
||
this.scrollBy(movement);
|
||
this._rows[activeRowKey].moveBy(movement);
|
||
} else {
|
||
this._stopAutoScroll();
|
||
}
|
||
}, AUTOSCROLL_INTERVAL);
|
||
}
|
||
|
||
_stopAutoScroll() {
|
||
clearInterval(this._autoScrollInterval);
|
||
this._autoScrollInterval = null;
|
||
}
|
||
|
||
_onLayoutRow(rowKey, {nativeEvent: {layout}}) {
|
||
this._resolveRowLayout[rowKey]({rowKey, layout});
|
||
}
|
||
|
||
_onLayoutHeader = ({nativeEvent: {layout}}) => {
|
||
this._resolveHeaderLayout(layout);
|
||
};
|
||
|
||
_onLayoutFooter = ({nativeEvent: {layout}}) => {
|
||
this._resolveFooterLayout(layout);
|
||
};
|
||
|
||
_onActivateRow = (rowKey, index, e, gestureState, location) => {
|
||
this._activeRowLocation = location;
|
||
|
||
this.setState({
|
||
activeRowKey: rowKey,
|
||
activeRowIndex: index,
|
||
releasedRowKey: null,
|
||
scrollEnabled: false,
|
||
});
|
||
|
||
if (this.props.onActivateRow) {
|
||
this.props.onActivateRow(rowKey);
|
||
}
|
||
};
|
||
|
||
_onPressRow = (rowKey) => {
|
||
if (this.props.onPressRow) {
|
||
this.props.onPressRow(rowKey);
|
||
}
|
||
};
|
||
|
||
_onReleaseRow = (rowKey) => {
|
||
this._stopAutoScroll();
|
||
this.setState(({activeRowKey}) => ({
|
||
activeRowKey: null,
|
||
activeRowIndex: null,
|
||
releasedRowKey: activeRowKey,
|
||
scrollEnabled: this.props.scrollEnabled,
|
||
}));
|
||
|
||
if (this.props.onReleaseRow) {
|
||
this.props.onReleaseRow(rowKey, this.state.order);
|
||
}
|
||
};
|
||
|
||
_onMoveRow = (e, gestureState, location) => {
|
||
const prevMovingRowX = this._activeRowLocation.x;
|
||
const prevMovingRowY = this._activeRowLocation.y;
|
||
const prevMovingDirection = this._movingDirection;
|
||
|
||
this._activeRowLocation = location;
|
||
this._movingDirection = this.props.horizontal
|
||
? prevMovingRowX < this._activeRowLocation.x
|
||
: prevMovingRowY < this._activeRowLocation.y;
|
||
|
||
this._movingDirectionChanged = prevMovingDirection !== this._movingDirection;
|
||
this._setOrderOnMove();
|
||
|
||
if (this.props.scrollEnabled) {
|
||
this._scrollOnMove(e);
|
||
}
|
||
};
|
||
|
||
_onScroll = (e) => {
|
||
this._contentOffset = e.nativeEvent.contentOffset;
|
||
this.props.onScroll(e)
|
||
};
|
||
|
||
_onRefContainer = (component) => {
|
||
this._container = component;
|
||
};
|
||
|
||
_onRefScrollView = (component) => {
|
||
this._scrollView = component;
|
||
};
|
||
|
||
_onRefRow = (rowKey, component) => {
|
||
this._rows[rowKey] = component;
|
||
};
|
||
}
|
||
|
||
const styles = StyleSheet.create({
|
||
container: {
|
||
flex: 1,
|
||
},
|
||
|
||
rowsContainer: {
|
||
flex: 1,
|
||
zIndex: 1,
|
||
},
|
||
});
|