ReactNative學習筆記十一之FlatList

mymdeep發表於2019-03-02

之前使用的元件是ListView,當時要新增一個下拉重新整理,上拉載入的功能,所以對ListView做了一些封裝,但是後來看官方文件,不建議再使用ListView,因為效率問題,做過Android的朋友都知道,Android的ListView如果不自己處理一下,也是有效率問題的。所以官方又推出了FlatList,而且自帶上拉下拉的功能。


功能簡介

  • 完全跨平臺。
  • 支援水平佈局模式。
  • 行元件顯示或隱藏時可配置回撥事件。
  • 支援單獨的頭部元件。
  • 支援單獨的尾部元件。
  • 支援自定義行間分隔線。
  • 支援下拉重新整理。
  • 支援上拉載入。
  • 支援跳轉到指定行(ScrollToIndex)。
    如果需要分組/類/區(section),請使用SectionList(這個我們會在之後的文章中介紹)

    使用

    FlatList如果只做簡單使用也是很簡單的,這裡我們會分難以程度,逐漸介紹:

    直接使用

    <FlatList
    data={[{key: 'a'}, {key: 'b'}]}
    renderItem={({item}) => <Text>{item.key}</Text>}
    />複製程式碼
    可以看出跟之前的ListView很像,但是其中少了dataSource,這裡,我們只需要傳遞資料,其它的都交給FlatList處理好了。

    屬性說明

  • ItemSeparatorComponent
    行與行之間的分隔線元件。不會出現在第一行之前和最後一行之後。在這裡可以根據需要插入一個view

  • ListEmptyComponent
    列表為空時渲染該元件。可以是React Component, 也可以是一個render函式, 或者渲染好的element。

  • ListFooterComponent
    尾部元件

  • ListHeaderComponent
    頭部元件

  • columnWrapperStyle
    如果設定了多列布局(即將numColumns
    值設為大於1的整數),則可以額外指定此樣式作用在每行容器上。

  • data
    為了簡化起見,data屬性目前只支援普通陣列。如果需要使用其他特殊資料結構,例如immutable陣列,請直接使用更底層的VirtualizedList
    元件。

  • extraData
    如果有除data以外的資料用在列表中(不論是用在renderItem
    還是Header或者Footer中),請在此屬性中指定。同時此資料在修改時也需要先修改其引用地址(比如先複製到一個新的Object或者陣列中),然後再修改其值,否則介面很可能不會重新整理。

  • getItem
    獲取每個Item

  • getItemCount
    獲取Item屬相

  • getItemLayout
    是一個可選的優化,用於避免動態測量內容尺寸的開銷,不過前提是你可以提前知道內容的高度。如果你的行高是固定的getItemLayout
    用起來就既高效又簡單,類似下面這樣:
    getItemLayout={(data, index) => ( {length: 行高, offset: 行高 * index, index} )}注意如果你指定了SeparatorComponent,請把分隔線的尺寸也考慮到offset的計算之中。

  • horizontal
    設定為true則變為水平佈局模式。

  • initialNumToRender
    指定一開始渲染的元素數量,最好剛剛夠填滿一個螢幕,這樣保證了用最短的時間給使用者呈現可見的內容。注意這第一批次渲染的元素不會在滑動過程中被解除安裝,這樣是為了保證使用者執行返回頂部的操作時,不需要重新渲染首批元素。

  • initialScrollIndex
    指定渲染開始的item index

  • keyExtractor
    此函式用於為給定的item生成一個不重複的key。Key的作用是使React能夠區分同類元素的不同個體,以便在重新整理時能夠確定其變化的位置,減少重新渲染的開銷。若不指定此函式,則預設抽取item.key作為key值。若item.key也不存在,則使用陣列下標。

  • legacyImplementation
    設定為true則使用舊的ListView的實現。

  • numColumns
    多列布局只能在非水平模式下使用,即必須是horizontal={false}
    。此時元件內元素會從左到右從上到下按Z字形排列,類似啟用了flexWrap的佈局。元件內元素必須是等高的——暫時還無法支援瀑布流佈局。

  • onEndReached
    當列表被滾動到距離內容最底部不足onEndReachedThreshold
    的距離時呼叫。

  • onEndReachedThreshold
    決定當距離內容最底部還有多遠時觸發onEndReached
    回撥。注意此引數是一個比值而非畫素單位。比如,0.5表示距離內容最底部的距離為當前列表可見長度的一半時觸發。

  • onRefresh
    如果設定了此選項,則會在列表頭部新增一個標準的RefreshControl
    控制元件,以便實現“下拉重新整理”的功能。同時你需要正確設定refreshing
    屬性。

  • onViewableItemsChanged
    在可見行元素變化時呼叫。可見範圍和變化頻率等引數的配置請設定viewabilityconfig屬性

  • refreshing
    在等待載入新資料時將此屬性設為true,列表就會顯示出一個正在載入的符號。

  • renderItem
    根據行資料data,渲染每一行的元件。這個參照下面的demo

  • viewabilityConfig
    請參考ViewabilityHelper 的原始碼來了解具體的配置。

方法

  • scrollToEnd
    滾動到底部。如果不設定getItemLayout
    屬性的話,可能會比較卡。

  • scrollToIndex
    滾動到指定index的item
    如果不設定getItemLayout
    屬性的話,無法跳轉到當前可視區域以外的位置。

  • scrollToItem
    滾動到指定item,如果不設定getItemLayout
    屬性的話,可能會比較卡。

  • scrollToOffset
    滾動指定距離

進階使用

在這裡我準備了一份程式碼示例:


const {width,height}=Dimensions.get('window')
export default class Main extends Component{
    // 構造
    constructor(props) {
        super(props);
    }
    refreshing(){
        let timer =  setTimeout(()=>{
                    clearTimeout(timer)
                    alert('重新整理成功')
                },1500)
    }
    _onload(){
        let timer =  setTimeout(()=>{
            clearTimeout(timer)
            alert('載入成功')
        },1500)
    }
    render() {
        var data = [];
        for (var i = 0; i < 100; i++) {
            data.push({key: i, title: i + ''});
        }

        return (
            <View style={{flex:1}}>
                <Button title='滾動到指定位置' onPress={()=>{
                    this._flatList.scrollToOffset({animated: true, offset: 2000});
                }}/>
                <View style={{flex:1}}>
                    <FlatList
                        ref={(flatList)=>this._flatList = flatList}
                        ListHeaderComponent={this._header}
                        ListFooterComponent={this._footer}
                        ItemSeparatorComponent={this._separator}
                        renderItem={this._renderItem}
                        onRefresh={this.refreshing}
                        refreshing={false}
                        onEndReachedThreshold={0}
                        onEndReached={
                            this._onload
                        }
                        numColumns ={3}
                        columnWrapperStyle={{borderWidth:2,borderColor:'black',paddingLeft:20}}

                        //horizontal={true}

                        getItemLayout={(data,index)=>(
                        {length: 100, offset: (100+2) * index, index}
                        )}

                        data={data}>
                    </FlatList>
                </View>

            </View>
        );
    }


    _renderItem = (item) => {
        var txt = '第' + item.index + '個' + ' title=' + item.item.title;
        var bgColor = item.index % 2 == 0 ? 'red' : 'blue';
        return <Text style={[{flex:1,height:100,backgroundColor:bgColor},styles.txt]}>{txt}</Text>
    }

    _header = () => {
        return <Text style={[styles.txt,{backgroundColor:'black'}]}>這是頭部</Text>;
    }

    _footer = () => {
        return <Text style={[styles.txt,{backgroundColor:'black'}]}>這是尾部</Text>;
    }

    _separator = () => {
        return <View style={{height:2,backgroundColor:'yellow'}}/>;
    }


}
const styles=StyleSheet.create({
    container:{

    },
    content:{
        width:width,
        height:height,
        backgroundColor:'yellow',
        justifyContent:'center',
        alignItems:'center'
    },
    cell:{
        height:100,
        backgroundColor:'purple',
        alignItems:'center',
        justifyContent:'center',
        borderBottomColor:'#ececec',
        borderBottomWidth:1

    },
    txt: {
        textAlign: 'center',
        textAlignVertical: 'center',
        color: 'white',
        fontSize: 30,
    }

})複製程式碼

執行效果如下:

總結

總體來說Flatlist還是比ListView用起來方便的,而且提供的功能更多。


之前文章合集:
Android文章合集
iOS文章合集
ReactNative文章合集
如果你也做ReactNative開發,並對ReactNative感興趣,歡迎關注我的公眾號,加入我們的討論群:

相關文章