RN笔记—SectionList

SectionList 是一个高性能的分组列表组件。它可以简单的给一组数据进行分组渲染,它支持一下的功能:

  • 完全跨平台。
  • 支持水平布局模式。
  • 行组件显示或隐藏时可配置回调事件。
  • 支持单独的头部组件。
  • 支持单独的尾部组件。
  • 支持自定义行间分隔线。
  • 支持下拉刷新。
  • 支持上拉加载。

注意:SectionList的实质是基于<VirtualizedList>组件的封装,因此也有以下这些需要注意的地方。

  • 当某行滑出渲染区域之外后,其内部状态将不会保留。请确保你在行组件以外的地方保留了数据。
  • 本组件继承自PureComponent而非通常的Component,这意味着如果其props浅比较中是相等的,则不会重新渲染。所以请先检查你的renderItem函数所依赖的props数据(包括data属性以及可能用到的父组件的state),如果是一个引用类型(Object或者数组都是引用类型),则需要先修改其引用地址(比如先复制到一个新的Object或者数组中),然后再修改其值,否则界面很可能不会刷新。(译注:这一段不了解的朋友建议先学习下js中的基本类型和引用类型。)
  • 为了优化内存占用同时保持滑动的流畅,列表内容会在屏幕外异步绘制。这意味着如果用户滑动的速度超过渲染的速度,则会先看到空白的内容。
  • 默认情况下每行都需要提供一个不重复的key属性。你也可以提供一个keyExtractor函数来生成key。

SectionList常用属性和方法

1、属性集合

属性名 类型 说明
sections Array 数据源
ItemSeparatorComponent ReactClass<any> 行与行之间的分隔线组件。不会出现在第一行之前和最后一行之后
SectionSeparatorComponent ReactClass<any> 每个section之间的分隔组件
ListEmptyComponent ReactClass<any> React.Element<any> 列表为空时渲染该组件。可以是React Component, 也可以是一个render函数, 或者渲染好的element。
ListFooterComponent ReactClass<any> 尾部组件
ListHeaderComponent ReactClass<any> 头部组件
data Array<ItemT> 为了简化起见,data属性目前只支持普通数组。如果需要使用其他特殊数据结构,例如immutable数组,请直接使用更底层的VirtualizedList组件
extraData any 如果有除data以外的数据用在列表中(不论是用在renderItem还是Header或者Footer中),请在此属性中指定。同时此数据在修改时也需要先修改其引用地址(比如先复制到一个新的Object或者数组中),然后再修改其值,否则界面很可能不会刷新。
getItem any 获取控件的绑定数据
getItemCount any 获取绑定数据的条数
getItemLayout (data: ?Array<ItemT>, index: number) => {length: number, offset: number, index: number} getItemLayout是一个可选的优化,用于避免动态测量内容尺寸的开销,不过前提是你可以提前知道内容的高度。如果你的行高是固定的,getItemLayout,用起来就既高效又简单,类似下面这样:getItemLayout={(data, index) => ( {length: 行高, offset: 行高 * index, index} )}注意如果你指定了SeparatorComponent,请把分隔线的尺寸也考虑到offset的计算之中。
initialNumToRender number 指定一开始渲染的元素数量,最好刚刚够填满一个屏幕,这样保证了用最短的时间给用户呈现可见的内容。注意这第一批次渲染的元素不会在滑动过程中被卸载,这样是为了保证用户执行返回顶部的操作时,不需要重新渲染首批元素。
keyExtractor (item: ItemT, index: number) => string 此函数用于为给定的item生成一个不重复的key。Key的作用是使React能够区分同类元素的不同个体,以便在刷新时能够确定其变化的位置,减少重新渲染的开销。若不指定此函数,则默认抽取item.key作为key值。若item.key也不存在,则使用数组下标。
legacyImplementation boolean 设置为true则使用旧的ListView的实现
onEndReached (info: {distanceFromEnd: number}) => void 当列表被滚动到距离内容最底部不足onEndReachedThreshold的距离时调用
onEndReachedThreshold number 决定当距离内容最底部还有多远时触发onEndReached回调。注意此参数是一个比值而非像素单位。比如,0.5表示距离内容最底部的距离为当前列表可见长度的一半时触发
onRefresh void 如果设置了此选项,则会在列表头部添加一个标准的RefreshControl控件,以便实现“下拉刷新”的功能。同时你需要正确设置refreshing属性
onViewableItemsChanged (info: {viewableItems: Array<ViewToken>, changed: Array<ViewToken>}) => void 在可见行元素变化时调用。可见范围和变化频率等参数的配置请设置viewabilityconfig属性
refreshing boolean 在等待加载新数据时将此属性设为true,列表就会显示出一个正在加载的符号
renderItem (info: {item: ItemT, index: number}) => ?React.Element<any> 根据行数据data渲染每一行的组件
viewabilityConfig ViewabilityConfig 2请参考ViewabilityHelper的源码来了解具体的配置

2、方法集合

方法名 说明
scrollToLocation 将可视区内位于特定sectionIndex 或 itemIndex (section内)位置的列表项,滚动到可视区的制定位置。比如说,viewPosition 为0时将这个列表项滚动到可视区顶部 (可能会被顶部粘接的header覆盖), 为1时将它滚动到可视区底部, 为0.5时将它滚动到可视区中央。viewOffset是一个以像素为单位,到最终位置偏移距离的固定值,比如为了弥补粘接的header所占据的空间。注意: 如果没有设置getItemLayout,就不能滚动到位于外部渲染区的位置。
recordInteraction 主动通知列表发生了一个事件,以使列表重新计算可视区域。比如说当waitForInteractions 为 true 并且用户没有滚动列表时,就可以调用这个方法。不过一般来说,当用户点击了一个列表项,或发生了一个导航动作时,我们就可以调用这个方法。
flashScrollIndicators 短暂地显示滚动指示器。

这里需要注意的点:
1.renderSectionHeader里面的参数必须是{section},不然无效。
2.renderItem里面的参数必须是{item},不然无效。
3.后台返回的json数据格式必须是data+title这种,开始还很疑惑不规定格式下是如何找到是哪行的。
4.key如果没有加的话会出现数据加载不出的问题(虽然我没出现过)。为了安全起见我加了key并且给sectionList加了keyExtractor。

3、示例代码

import React, { Component } from 'react';
import {AppRegistry, StyleSheet, View, Text, SectionList} from 'react-native';
export default class App extends Component {

  constructor(props) {
    super(props);
  }

  render() {
    let sections =[
      {typeName:"导演", persons:[{name:"唐季礼"}]},
      {typeName:"演员",persons:[{name:"成龙"},{name: "李治廷"}]}];
    
    //这里要对数组转换一下,
    // 因为SectionList要求item必须是data的数组,
    // 如果把data写成其他单词则会报错
    //不管你是否使用一个或多个不同的section,都要重新定义以下section如:
    // tempData.key = item.typeName;    
    // temData.key =`${item.typeName} ${item.typeNameEn}`
   //   tempData.typeName = item.typeName; tempData.key = item.typeNameEn
    let tempArr = sections.map((item, index) => {     
      let tempData = {};                             
      tempData.key = item.typeName;                
      tempData.data = item.persons;
      return tempData
    });

    return (
        <View style={{ flex: 1 }}>
          <SectionList
              renderSectionHeader={this.renderSectionHeader}
              renderItem={this.renderItem}
              sections={tempArr}
              ItemSeparatorComponent={() => <View><Text></Text></View>}
              ListHeaderComponent={() => <View style={{ backgroundColor: '#25B960', alignItems: 'center', height: 30 }}><Text style={{ fontSize: 18, color: '#ffffff' }}>通讯录</Text></View>}
              ListFooterComponent={() => <View style={{ backgroundColor: '#25B960', alignItems: 'center', height: 30 }}><Text style={{ fontSize: 18, color: '#ffffff' }}>通讯录尾部</Text></View>}
          />
        </View>
    );
  }

  renderSectionHeader = (info) => {
    let section = info.section.key;
    return (<Text
        style={styles.sectionStyle}>{section}</Text>
    )
  };

  renderItem = (info) => {
    let item = info.item.name;
    return (
        <Text style={styles.itemStyle}>{item}</Text>
    )
  };
}

const styles = StyleSheet.create({
  itemStyle: {
    height: 60,
    textAlignVertical: 'center',
    backgroundColor: "#ffffff",
    color: '#5C5C5C',
    fontSize: 15
  },
  sectionStyle: {
    height: 50,
    textAlign: 'center',
    textAlignVertical: 'center',
    backgroundColor: '#9CEBBC',
    color: 'white',
    fontSize: 30
  }
});
AppRegistry.registerComponent('Demo', () => App);

这里要对数组转换一下,
因为SectionList要求item必须是data的数组,
如果把data写成其他单词则会报错
不管你是否使用一个或多个不同的section,都要重新定义以下section如:

tempData.key = item.typeName;   
 temData.key =`${item.typeName} ${item.typeNameEn}`
 tempData.typeName = item.typeName; 
 tempData.typeNameEn = item.typeNameEn'
image
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,734评论 6 505
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,931评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,133评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,532评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,585评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,462评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,262评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,153评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,587评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,792评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,919评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,635评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,237评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,855评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,983评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,048评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,864评论 2 354

推荐阅读更多精彩内容