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…