ReactNative: 使用分组列表组件SectionList组件
一、简介
SectionList,分组列表,ReactNative中继提供的ListView和FlatList列表组件后的又一个很重要的分组列表组件。它的用法其实跟前面的FlatList差不多,但是SectionList组件性能更高,同时SectionList组件要比ListView组件使用简单的多。SectionList组件的功能非常强大,如下所示。现在我们来仔细研究一下这个组件的API。
- 完全跨平台。
- 可配置的可见性回调。
- 列表标题支持。
- 列出页脚支持。
- 项目分隔符支持。
- 节标题支持。
- 部分分隔符支持。
- 异构数据和项目渲染支持。
- 拉动以刷新。
- 滚动加载。
二、API
SectionList组件同样地对属性是必须直接提供的,有些是可选的。如下所示:
//分组基类SectionBase对象结构, 泛型为SectionItemT type SectionBase<SectionItemT> = { //数据源数组,必需属性 data: Array<SectionItemT>, //每一组数据源的标识符 ,必需属性 key: string,
//每一组的每一个item组件,可选属性 renderItem?: ?(info: {item: SectionItemT, index: number}) => ?React.Element<any>, //分割线,可选属性 ItemSeparatorComponent?: ?ReactClass<any>, //标识符,可选属性 keyExtractor?: (item: SectionItemT) => string, }; //必要的属性 //sections,是一个泛型数组,类型为SectionT,存储的是SectionBase对象 type RequiredProps<SectionT: SectionBase<any>> = { sections: Array<SectionT>, }; //可选的属性 type OptionalProps<SectionT: SectionBase<any>> = { //每个部分中每个项目的默认渲染器。 可以逐段覆盖。 renderItem: (info: {item: Item, index: number}) => ?React.Element<any>, //在每个部分的相邻项目之间渲染。每一个item的分割线 ItemSeparatorComponent?: ?ReactClass<any>, //在列表的最开始呈现。表头 ListHeaderComponent?: ?ReactClass<any>, //呈现在列表的最后。表尾 ListFooterComponent?: ?ReactClass<any>, //在每个部分之间渲染。组分割线 SectionSeparatorComponent?: ?ReactClass<any>, //一个标记属性,用于告诉列表重新渲染(因为它实现了`PureComponent`)。
//如果您的`renderItem`,Header,Footer等函数中的任何一个都依赖于`data`道具之外的任何东西,请将其粘贴在这里并一视同仁。 extraData?: any, //页面初次渲染的个数,可以不用等所有页面渲染出来再显示UI initialNumToRender: number, //用于提取指定索引处给定项目的唯一键。 键用于缓存,并用作反应键以跟踪项的重新排序。 默认的提取器检查item.key,然后像react一样退回到使用索引。 keyExtractor: (item: Item, index: number) => string, //滚动位置在渲染内容的onEndReachedThreshold范围内时调用一次。 onEndReached?: ?(info: {distanceFromEnd: number}) => void, //列表的底边必须从内容的末尾到末尾(以列表的可见长度为单位)多远,才能触发onEndReached回调。
//因此,当内容的结尾在列表的可见长度的一半以内时,值为0.5将触发“ onEndReached”。 onEndReachedThreshold?: ?number, //如果提供,将为“拉动刷新”功能添加标准的RefreshControl。 onRefresh?: ?() => void, //当行的可视性发生变化时调用,如`viewabilityConfig`属性所定义。 onViewableItemsChanged?: ?(info: { viewableItems: Array<ViewToken>, changed: Array<ViewToken>, }) => void, //等待刷新之前的新数据时,将其设置为true。 refreshing?: ?boolean, //呈现在每个部分的顶部。 尚不支持粘性标头。组头 renderSectionHeader?: ?(info: {section: SectionT}) => ?React.Element<any>, //使节标题停留在屏幕顶部,直到下一个将其关闭。 仅在iOS上默认启用,因为这是该平台的平台标准。 stickySectionHeadersEnabled?: boolean, };
三、使用
看完API,可以发现接收的数据数组sections存储的都是SectionBase,而每一个SectionBase内部都必需包含data数组和key唯一标识,剩余的元素是可选的。其实挺简单的,现在来实现一下部分功能,示例如下:
MySectionListView.js
import React, { Component } from 'react'; import { StyleSheet, View, Image, Text, Dimensions, SectionList } from 'react-native'; const {width} = Dimensions.get('window'); const itemPadding = 20; const itemWidth = (width-4*itemPadding)/3; console.log('width:'+width); const fetch_data = [ { "type":"A", "flowers":[ { icon:require('../image/flower1.png'), title:'玫瑰' }, { icon:require('../image/flower1.png'), title:'玫瑰' }, { icon:require('../image/flower1.png'), title:'玫瑰' } ] }, { "type":"B", "flowers":[ { icon:require('../image/flower2.png'), title:'草芽' }, { icon:require('../image/flower2.png'), title:'草芽' }, { icon:require('../image/flower2.png'), title:'草芽' } ] }, { "type":"C", "flowers":[ { icon:require('../image/flower3.png'), title:'向日葵' }, { icon:require('../image/flower3.png'), title:'向日葵' }, { icon:require('../image/flower3.png'), title:'向日葵' } ] }, { "type":"D", "flowers":[ { icon:require('../image/flower4.png'), title:'月季' }, { icon:require('../image/flower4.png'), title:'月季' }, { icon:require('../image/flower4.png'), title:'月季' } ] } ]; export default class MySectionListView extends Component{ //渲染item info: {item: Item, index: number} _renderItem(info){ return ( <View style={styles.item}> <Image style={styles.image} source={info.item.icon}/> <Text style={styles.text}>{info.item.title}</Text> </View> ) } //渲染组头 info: {section: SectionT} _renderSectionHeader(info){ return ( <View style={styles.sectionHeader}> <Text key={info.section.key} style={{color:'white',fontSize: 25,justifyContent: 'center'}}> {info.section.type} </Text> </View> ) } //渲染表头 _listHeaderComponent(){ return ( <View style={{width:width,height:200,backgroundColor:'red'}}/> ) } //渲染表尾 _listFooterComponent(){ return ( <View style={{width:width,height:200,backgroundColor:'green'}}/> ) } render() { //sections数据源 let sections = []; for (let i = 0; i < fetch_data.length; i++) { //创建SectionBase对象,初始化key唯一标识,和data数组 let data = []; const type = fetch_data[i].type; const flowers = fetch_data[i].flowers; for(let j=0; j<flowers.length; j++){ data.push(flowers[j]); } sections.push({key: i, data: data, type:type}); } return ( <View style={styles.flex}> <SectionList sections={sections} renderItem={this._renderItem} keyExtractor={(item, index) => ("index:" + index + item)} contentContainerStyle={styles.section} renderSectionHeader={this._renderSectionHeader} ListHeaderComponent={this._listHeaderComponent} ListFooterComponent={this._listFooterComponent} /> </View> ); } } const styles = StyleSheet.create({ flex: { flex: 1, }, center: { alignItems: 'center', justifyContent: 'center' }, section: { flexDirection: 'row', flexWrap: 'wrap', backgroundColor:'#EEE' }, item: { width: itemWidth, marginTop: 10, marginBottom: 10, marginLeft: itemPadding, justifyContent: 'center', backgroundColor: '#21c6cd' }, image: { width: itemWidth, height: 150 }, text: { marginTop: 5, width: itemWidth, fontSize: 25, textAlign: 'center' }, sectionHeader: { height: 30, width: width, backgroundColor: 'gray' } });
程序猿神奇的手,每时每刻,这双手都在改变着世界的交互方式!