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'
   }
});

 

posted @ 2020-01-08 17:17  XYQ全哥  阅读(1111)  评论(0编辑  收藏  举报