API update and bug fixes

Reviewed By: bvaughn, yungsters

Differential Revision: D4563798

fbshipit-source-id: 0591cef7c854b525d77e526af783284d9696cb48
This commit is contained in:
Spencer Ahrens 2017-02-16 18:59:59 -08:00 committed by Facebook Github Bot
parent 5042bae259
commit 6283878e17
4 changed files with 56 additions and 38 deletions

View File

@ -35,7 +35,7 @@ const {
View,
} = ReactNative;
type Item = {title: string, text: string, key: number, pressed: boolean};
type Item = {title: string, text: string, key: number, pressed: boolean, noImage?: ?boolean};
function genItemData(count: number): Array<Item> {
const dataBlob = [];
@ -73,7 +73,7 @@ class ItemComponent extends React.PureComponent {
style={horizontal ? styles.horizItem : styles.item}>
<View style={[
styles.row, horizontal && {width: HORIZ_WIDTH}]}>
<Image style={styles.thumb} source={imgSource} />
{!item.noImage && <Image style={styles.thumb} source={imgSource} />}
<Text
style={styles.text}
numberOfLines={(horizontal || fixedHeight) ? 3 : undefined}>
@ -108,7 +108,7 @@ class FooterComponent extends React.PureComponent {
<View>
<SeparatorComponent />
<View style={styles.headerFooter}>
<Text>FOOTER</Text>
<Text>LIST FOOTER</Text>
</View>
</View>
);
@ -120,7 +120,7 @@ class HeaderComponent extends React.PureComponent {
return (
<View>
<View style={styles.headerFooter}>
<Text>HEADER</Text>
<Text>LIST HEADER</Text>
</View>
<SeparatorComponent />
</View>
@ -164,7 +164,7 @@ function hashCode(str: string): number {
return hash;
}
const HEADER = {height: 30, width: 80};
const HEADER = {height: 30, width: 100};
const SEPARATOR_HEIGHT = StyleSheet.hairlineWidth;
function getItemLayout(data: any, index: number, horizontal?: boolean) {

View File

@ -36,6 +36,7 @@ const UIExplorerPage = require('./UIExplorerPage');
const infoLog = require('infoLog');
const {
HeaderComponent,
FooterComponent,
ItemComponent,
PlainInput,
@ -53,10 +54,10 @@ const SectionHeaderComponent = ({section}) => (
</View>
);
const SectionSeparatorComponent = () => (
const CustomSeparatorComponent = ({text}) => (
<View>
<SeparatorComponent />
<Text style={styles.sectionSeparatorText}>SECTION SEPARATOR</Text>
<Text style={styles.separatorText}>{text}</Text>
<SeparatorComponent />
</View>
);
@ -94,20 +95,25 @@ class SectionListExample extends React.PureComponent {
</View>
<SeparatorComponent />
<SectionList
FooterComponent={FooterComponent}
ListHeaderComponent={HeaderComponent}
ListFooterComponent={FooterComponent}
ItemComponent={this._renderItemComponent}
SectionHeaderComponent={SectionHeaderComponent}
SectionSeparatorComponent={SectionSeparatorComponent}
SeparatorComponent={SeparatorComponent}
SectionSeparatorComponent={() => <CustomSeparatorComponent text="SECTION SEPARATOR" />}
ItemSeparatorComponent={() => <CustomSeparatorComponent text="ITEM SEPARATOR" />}
enableVirtualization={this.state.virtualized}
onRefresh={() => alert('onRefresh: nothing to refresh :P')}
onViewableItemsChanged={this._onViewableItemsChanged}
refreshing={false}
sections={[
{ItemComponent: StackedItemComponent, key: 's1', data: [
{title: 'Item In Header Section', text: 's1', key: '0'}
{title: 'Item In Header Section', text: 'Section s1', key: '0'},
]},
{key: 's2', data: filteredData},
{key: 's2', data: [
{noImage: true, title: 'First item', text: 'Section s2', key: '0'},
{noImage: true, title: 'Second item', text: 'Section s2', key: '1'},
]},
{key: 'Filtered Items', data: filteredData},
]}
viewablePercentThreshold={100}
/>
@ -143,11 +149,11 @@ const styles = StyleSheet.create({
searchRow: {
paddingHorizontal: 10,
},
sectionSeparatorText: {
separatorText: {
color: 'gray',
alignSelf: 'center',
padding: 4,
fontWeight: 'bold',
fontSize: 9,
},
});

View File

@ -66,27 +66,30 @@ type RequiredProps<SectionT: SectionBase<*>> = {
};
type OptionalProps<SectionT: SectionBase<*>> = {
/**
* Rendered after the last item in the last section.
*/
FooterComponent?: ?ReactClass<*>,
/**
* Default renderer for every item in every section.
*/
ItemComponent: ReactClass<{item: Item, index: number}>,
/**
* Rendered at the top of each section. In the future, a sticky option will be added.
* Rendered in between adjacent Items within each section.
*/
ItemSeparatorComponent?: ?ReactClass<*>,
/**
* Rendered at the very beginning of the list.
*/
ListHeaderComponent?: ?ReactClass<*>,
/**
* Rendered at the very end of the list.
*/
ListFooterComponent?: ?ReactClass<*>,
/**
* Rendered at the top of each section. Sticky headers are not yet supported.
*/
SectionHeaderComponent?: ?ReactClass<{section: SectionT}>,
/**
* Rendered at the bottom of every Section, except the very last one, in place of the normal
* SeparatorComponent.
* Rendered in between each section.
*/
SectionSeparatorComponent?: ?ReactClass<*>,
/**
* Rendered at the bottom of every Item except the very last one in the last section.
*/
SeparatorComponent?: ?ReactClass<*>,
/**
* Warning: Virtualization can drastically improve memory consumption for long lists, but trashes
* the state of items when they scroll out of the render window, so make sure all relavent data is
@ -143,11 +146,16 @@ class SectionList<SectionT: SectionBase<*>>
static defaultProps: DefaultProps = VirtualizedSectionList.defaultProps;
render() {
if (this.props.legacyImplementation) {
return <MetroListView {...this.props} items={this.props.sections} />;
} else {
return <VirtualizedSectionList {...this.props} />;
}
const {ListFooterComponent, ListHeaderComponent, ItemSeparatorComponent} = this.props;
const List = this.props.legacyImplementation ? MetroListView : VirtualizedSectionList;
return (
<List
{...this.props}
FooterComponent={ListFooterComponent}
HeaderComponent={ListHeaderComponent}
SeparatorComponent={ItemSeparatorComponent}
/>
);
}
}

View File

@ -163,14 +163,18 @@ class VirtualizedSectionList<SectionT: SectionBase>
const defaultKeyExtractor = this.props.keyExtractor;
for (let ii = 0; ii < this.props.sections.length; ii++) {
const section = this.props.sections[ii];
const keyExtractor = section.keyExtractor || defaultKeyExtractor;
const key = keyExtractor(section, ii);
const key = section.key;
warning(
key != null,
'VirtualizedSectionList: A `section` you supplied is missing the `key` property.'
);
itemIndex -= 1; // The section itself is an item
if (itemIndex >= section.data.length) {
itemIndex -= section.data.length;
} else if (itemIndex === -1) {
return {section, key, index: null};
} else {
const keyExtractor = section.keyExtractor || defaultKeyExtractor;
return {
section,
key: key + ':' + keyExtractor(section.data[itemIndex], itemIndex),
@ -216,7 +220,8 @@ class VirtualizedSectionList<SectionT: SectionBase>
if (!info) {
return null;
} else if (info.index == null) {
return <this.props.SectionHeaderComponent section={info.section} />;
const {SectionHeaderComponent} = this.props;
return SectionHeaderComponent ? <SectionHeaderComponent section={info.section} /> : null;
} else {
const ItemComponent = info.section.ItemComponent || this.props.ItemComponent;
const SeparatorComponent = this._getSeparatorComponent(index, info);
@ -236,13 +241,12 @@ class VirtualizedSectionList<SectionT: SectionBase>
}
const SeparatorComponent = info.section.SeparatorComponent || this.props.SeparatorComponent;
const {SectionSeparatorComponent} = this.props;
const lastItemIndex = this.state.childProps.getItemCount() - 1;
if (SectionSeparatorComponent &&
info.index === info.section.data.length - 1 &&
index < lastItemIndex) {
const isLastItemInList = index === this.state.childProps.getItemCount() - 1;
const isLastItemInSection = info.index === info.section.data.length - 1;
if (SectionSeparatorComponent && isLastItemInSection && !isLastItemInList) {
return SectionSeparatorComponent;
}
if (SeparatorComponent && index < lastItemIndex) {
if (SeparatorComponent && !isLastItemInSection && !isLastItemInList) {
return SeparatorComponent;
}
return null;