ListView - 一个核心组件,用于高效地显示一个能够垂直滚动的变化的数据列表。最基本的使用方式就是建立一个
ListView.DataSource
数据源,而后给它传递一个普通的数据数组,再使用数据源来实例化一个ListView
组件,而且定义它的renderRow
回调函数,这个函数会接受数组中的每一个数据做为参数,返回一个可渲染的组件(做为listview的每一行)javascript
简单说它就是一个列表组件,用来显示列表视图,相似Android中的ListView,iOS中的UITableView。做为列表组件,ListView是很是经常使用的。虽然官方文档中指出ListView已通过期,指定FlatList和SectionList替代ListView来使用,但我认为仍是有必要对这个控件加深理解,在不少状况下使用ListView仍是很方便的。html
这里我只列出日常会用的比较多的重要属性加以讲解,其它属性能够查阅官方文档。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的状况。
第一种,简单列表视图的实现
如图,要实现这样一个列表,咱们只须要设置数据源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的内容样式改变后里面的全部元素都受到影响,要么所有纵向显示,要么所有横向显示,达不到咱们想要的效果。这里有两种方法:
{ sectionID_1: [ rowData1, rowData2, ... ], sectionID_2: [rowData], sectionID_3: [ rowData1, rowData2, ... ], ...}复制代码
或者
[[ rowData1, rowData2, ... ], [ rowData], [ rowData1, rowData2, ... ], ...]复制代码
其中sectionID_2的分组就是要用来显示网格视图的。以上两种方式其实原理一致,只不过使用控件不一样。这部分的实现相对来讲稍微复杂点,在Demo中我分了两种状况实现,具体逻辑请看demo。
这里须要说明的是,对于多个section的ListView和单一section的ListView,dataSource的实现是不同的。
let ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
this.state = { dataSource: ds.cloneWithRows(data)}复制代码
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…