react-native-mc-listview
Version:
A high performance FlatList providing customised pull-to-refresh | auto-pagination & infinite-scrolling | gridview layout | swipeable-row. The truly ultimate version that I have done the most tricky part for you, just simply follow the instructions shown
158 lines (144 loc) • 4.8 kB
JavaScript
/* eslint-disable*/
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import {
View,
Text,
FlatList,
ScrollView,
LayoutAnimation,
TouchableOpacity,
} from 'react-native';
class ExpandableList extends Component {
constructor(props) {
super(props);
this.flatList;
this.layoutStore = [];
let map = new Map();
if (props.dataSource && props.isOpen) {
props.dataSource.map((item, i) => map.set(i, true))
}
if (props.openOptions) {
props.openOptions.map((item) => map.set(item, true))
}
this.state = {
memberOpened: map
}
}
static propTypes = {
dataSource: PropTypes.array.isRequired,
headerKey: PropTypes.string,
memberKey: PropTypes.string,
renderRow: PropTypes.func,
renderSectionHeaderX: PropTypes.func,
renderSectionFooterX: PropTypes.func,
headerOnPress: PropTypes.func,
isOpen: PropTypes.bool,
openOptions: PropTypes.array,
rowNumberCloseMode: PropTypes.number,
};
static defaultProps = {
headerKey: 'header',
memberKey: 'member',
isOpen: false,
rowNumberCloseMode: 0,
};
_keyExtractor = (item, index) => index.toString();
scrollToEnd = (params) => this.flatList.scrollToEnd(params);
scrollToIndex = (params) => this.flatList.scrollToIndex(params);
scrollToItem = (params) => this.flatList.scrollToItem(params);
scrollToOffset = (params) => this.flatList.scrollToOffset(params);
recordInteraction = (params) => this.flatList.recordInteraction();
flashScrollIndicators = (params) => this.flatList.flashScrollIndicators();
scrollToSection = ({ animated, section }) => {
let offset = 0;
this.layoutStore.forEach((item, index) => {
if (index < section) {
offset = offset + item.layout.height
}
});
this.flatList.scrollToOffset({ animated, offset });
};
setSectionState = (index, state) => {
this.setState((s) => {
const memberOpened = new Map(s.memberOpened);
memberOpened.set(index, state); // toggle
return {memberOpened};
});
LayoutAnimation.easeInEaseOut();
}
_onPress = (i) => {
this.setState((state) => {
const memberOpened = new Map(state.memberOpened);
memberOpened.set(i, !memberOpened.get(i)); // toggle
return { memberOpened };
});
if (this.props.headerOnPress) {
this.props.headerOnPress(i, !(!!this.state.memberOpened.get(i)));
}
LayoutAnimation.easeInEaseOut();
};
_itemLayout = (e) => {
const target = e.nativeEvent.target;
if (this.layoutStore.filter(item => item.target === target)[0]) {
this.layoutStore = this.layoutStore.map((item, index) => {
if (item.target === target) return e.nativeEvent;
return item;
});
} else {
this.layoutStore.push(e.nativeEvent);
this.layoutStore.length === this.props.dataSource.length &&
this.layoutStore.sort((v1, v2) => v1.target - v2.target);
}
};
_renderItem = ({ item, index }) => { // eslint-disable-line
const { renderRow, renderSectionHeaderX, renderSectionFooterX, headerKey,
memberKey, rowNumberCloseMode } = this.props;
const sectionId = index;
let memberArr = item[memberKey] || [];
if (!this.state.memberOpened.get(sectionId) && memberArr.length > rowNumberCloseMode) {
memberArr = memberArr.slice(0, rowNumberCloseMode);
}
return (
<View onLayout={this._itemLayout}>
<TouchableOpacity onPress={() => this._onPress(sectionId)}>
{ renderSectionHeaderX ? renderSectionHeaderX(item[headerKey], sectionId,
!!this.state.memberOpened.get(sectionId)) : null}
</TouchableOpacity>
<ScrollView scrollEnabled={false}>
{
memberArr.map((rowItem, rowId) => {
return (
<View key={rowId}>
{renderRow ? renderRow(rowItem, rowId, index) : null}
</View>
);
})
}
{ memberArr.length > 0 && renderSectionFooterX ? renderSectionFooterX(item, sectionId) : null }
</ScrollView>
</View>
);
};
_getItemLayout = (data, index) => {
let offset = 0;
this.layoutStore.forEach(item => offset = offset + item.layout.height);
this.props.getItemLayout && this.props.getItemLayout(data, index);
return { length: offset / index, offset: offset, index };
};
render() {
const { dataSource } = this.props;
return (
<FlatList
keyExtractor={this._keyExtractor}
extraData={this.state}
{...this.props}
ref={instance => this.flatList = instance}
data={dataSource}
horizontal={false}
renderItem={this._renderItem}
/>
);
}
}
export default ExpandableList;