React Native——ListView的使用详解

ListView是什么

ListView - 一个核心组件,用于高效地显示一个能够垂直滚动的变化的数据列表。最基本的使用方式就是建立一个ListView.DataSource数据源,而后给它传递一个普通的数据数组,再使用数据源来实例化一个ListView组件,而且定义它的renderRow回调函数,这个函数会接受数组中的每一个数据做为参数,返回一个可渲染的组件(做为listview的每一行)javascript

简单说它就是一个列表组件,用来显示列表视图,相似Android中的ListView,iOS中的UITableView。做为列表组件,ListView是很是经常使用的。虽然官方文档中指出ListView已通过期,指定FlatList和SectionList替代ListView来使用,但我认为仍是有必要对这个控件加深理解,在不少状况下使用ListView仍是很方便的。html

ListView的相关属性

这里我只列出日常会用的比较多的重要属性加以讲解,其它属性能够查阅官方文档。java

dataSource——ListView.DataSource实例,用来设置列表数据源react

renderRow——方法,用来渲染列表中每一行,该方法有四个参数(rowData, sectionID, rowID, highlightRow),能够经过传递参数来设置每行的数据,区分不一样的section和row。四个参数分别表示数据源中一条数据,分组的ID,行的ID,以及标记是不是高亮选中的状态信息。git

有了dataSource和renderRow这两个属性,咱们就能够完成一个ListView视图了,这两个属性是ListView最基本的属性,是必需要设置的。github

renderHeader——渲染头部视图,以iOS为例,UITableView有一个tableHeaderView属性,能够设置头部视图,这里renderHeader也能够渲染一个自定义的头部视图。react-native

renderFooter——渲染底部视图,相似于UITableView组件的tableFooterView,能够设置一个尾部视图。数组

renderSectionHeader——为每一个section渲染一个粘性的头部视图,相似于UITableView中的sectionHeader视图。bash

stickySectionHeadersEnabled——sectionHeader是否支持粘性,实际就是是否支持ListView在滑动时当前sectionHeader悬停在上方。这个效果跟UITableView中plain样式的sectionHeader效果同样。函数

renderSeparator——渲染每行的分割线,一般我不习惯这么作,能够直接在renderRow中给行视图底部设置一个宽度,使用borderBottomWidth和borderColor来实现分割线。

onEndReached——当全部的数据都已经渲染过,而且列表被滚动到距离最底部不足onEndReachedThreshold个像素的距离时调用。这个方法就是咱们用来作列表的上拉加载时用到的。

onEndReachedThreshold——这个属性在ListView中是数值,当列表被滚动到底部不足这个值的距离时会触发onEndReached中的方法。在FlatList和SectionList中这个值是比值0~1之间,这里须要区分清楚。

ListView的用法

本篇文章咱们使用ListView实现三种不一样的列表视图,基本能够涵盖咱们平常使用ListView的状况。

第一种,简单列表视图的实现

如图,要实现这样一个列表,咱们只须要设置数据源dataSource和renderRow就能够了。

在使用dataSource时,咱们须要先new一个dataSource对象,对于单个section的列表,使用rowHasChanged(prevRowData, nextRowData)和cloneWithRows(dataBlob, rowIdentities)来构造数据源。

对于每行视图,咱们须要一个image组件来显示图片,一个Text组件显示文本,使用TouchableOpacity组件将图片和文本包裹起来,并给它设置点击事件,renderRow就完成了。

代码以下:

constructor(props) {  
    super(props);  
    let ds = new ListView.DataSource({ rowHasChanged: (r1, r2) => r1 !== r2  });  
    this.state = {    
        dataSource: ds.cloneWithRows(data)  
    }
}

render() {  
    return (    
        <View style={styles.container}>      
            <ListView        
                dataSource={this.state.dataSource}        
                renderRow={this._renderRow}      
            />    
        </View>  
    )
}


_renderRow = (rowData) => {  
    return (    
        <TouchableOpacity style={styles.cellContainer} onPress={() => {}}>      
            <Image source={rowData.image} style={styles.image}/>      
            <Text style={styles.title}>{rowData.title}</Text>    
        </TouchableOpacity>  
    )
}
复制代码

其中data是一个包含图片和title的数组。经过设置数据源和渲染行视图的方式咱们就获得了一个简单的列表。

第二种,网格形式的列表

要实现这样一个Grid Layout的视图,其实很简单,只须要修改下上面的代码。将ListView内容的样式改成横向布局(flexDireaction:'row'),而后支持换行(flexWrap:'wrap'),renderRow中渲染的元素就会横向排列,若是全部元素一行显示不了就自动换行。

render() {  
    return (    
        <View style={{ flex: 1}}>      
            <ListView        
                contentContainerStyle={styles.listView}        
                dataSource={this.state.dataSource}        
                renderRow={this._renderRow}      
            />    
        </View>  
    )
}
复制代码

ListView是继承于ScrollView的,因此这里咱们能够给它设置内容样式,注意是contentContainerStyle而不是style。

listView: {  
    flexDirection:'row',  
    flexWrap:'wrap',  
    justifyContent:'space-between',  
    paddingLeft: 20,  
    paddingRight: 20,
},复制代码

而后调整renderRow中图片、文字和容器的样式,一个GridLayout的列表就完成了。

第三种,分组视图,包含单列和网格样式的列表

假设咱们有这样一个列表,有好几个分组(section),每一个section中的row显示样式不一样,有的是单列的,有的是网格形式的。这时候咱们就不能简单的像GridLayout那样将ListView的内容样式改变,由于ListView的内容样式改变后里面的全部元素都受到影响,要么所有纵向显示,要么所有横向显示,达不到咱们想要的效果。这里有两种方法:

  1. 对于网格元素的section,此section数据源咱们给它设置为只有一条数据的数组,在renderRow中使用一个View将全部子元素包裹起来,使用数组的map方法循环显示网格中的子元素。View的内容样式同GridLayout同样横向排列显示而后换行。分组的ListView数据源格式为
    { sectionID_1: [ rowData1, rowData2, ... ],  sectionID_2: [rowData], sectionID_3: [ rowData1, rowData2, ... ], ...}复制代码

    或者

    [[ rowData1, rowData2, ... ], [ rowData], [ rowData1, rowData2, ... ], ...]复制代码
    其中sectionID_2的分组就是要用来显示网格视图的。
  2. 在要显示网格元素的section中再嵌入一个ListView,方法同GridLayout同样。

以上两种方式其实原理一致,只不过使用控件不一样。这部分的实现相对来讲稍微复杂点,在Demo中我分了两种状况实现,具体逻辑请看demo。

这里须要说明的是,对于多个section的ListView和单一section的ListView,dataSource的实现是不同的。

  • 单一section
let ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
this.state = {  dataSource: ds.cloneWithRows(data)}复制代码
  • 多个section
let ds = new ListView.DataSource({  
    rowHasChanged: (r1, r2) => r1 !== r2,  
    sectionHeaderHasChanged: (s1, s2) => s1 !== s2
});
this.state = {  dataSource: ds.cloneWithRowsAndSections(data)}
复制代码

效果图以下

Demo地址: github.com/mrarronz/re…

相关文章
相关标签/搜索