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…

相關文章
相關標籤/搜索