react native FlatList使用详解以及上拉刷新下拉加载带可运行demo

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_34161388/article/details/72897292

                                       FlatList

高性能的简单列表组件,支持下面这些常用的功能:

  • 完全跨平台。
  • 支持水平布局模式。
  • 行组件显示或隐藏时可配置回调事件。
  • 支持单独的头部组件。
  • 支持单独的尾部组件。
  • 支持自定义行间分隔线。
  • 支持下拉刷新。
  • 支持上拉加载。
  • 支持跳转到指定行(ScrollToIndex)。

如果需要分组/类/区(section),请使用<SectionList>

一个最简单的例子:

<FlatList
  data={[{key: 'a'}, {key: 'b'}]}
  renderItem={({item}) => <Text>{item.key}</Text>}
/>

本组件实质是基于<VirtualizedList>组件的封装,因此也有下面这些需要注意的事项:

  • 当某行滑出渲染区域之外后,其内部状态将不会保留。请确保你在行组件以外的地方保留了数据。
  • 为了优化内存占用同时保持滑动的流畅,列表内容会在屏幕外异步绘制。这意味着如果用户滑动的速度超过渲染的速度,则会先看到空白的内容。这是为了优化不得不作出的妥协,而我们也在设法持续改进。
  • 本组件继承自PureComponent而非通常的Component,这意味着如果其props浅比较中是相等的,则不会重新渲染。所以请先检查你的renderItem函数所依赖的props数据(包括data属性以及可能用到的父组件的state),如果是一个引用类型(Object或者数组都是引用类型),则需要先修改其引用地址(比如先复制到一个新的Object或者数组中),然后再修改其值,否则界面很可能不会刷新。(译注:这一段不了解的朋友建议先学习下js中的基本类型和引用类型。)
  • 默认情况下每行都需要提供一个不重复的key属性。你也可以提供一个keyExtractor函数来生成key。

注意:removeClippedSubviews属性目前是不必要的,而且可能会引起问题。如果你在某些场景碰到内容不渲染的情况(比如使用LayoutAnimation时),尝试设置removeClippedSubviews={false}。我们可能会在将来的版本中修改此属性的默认值。


属性

ItemSeparatorComponent: ?ReactClass<any> 

行与行之间的分隔线组件。不会出现在第一行之前和最后一行之后。

ListFooterComponent?: ?ReactClass<any> 

尾部组件

ListHeaderComponent: ?ReactClass<any> 

头部组件

columnWrapperStyle: StyleObj 

如果设置了多列布局(即将numColumns值设为大于1的整数),则可以额外指定此样式作用在每行容器上。

data: ?Array<ItemT> 

为了简化起见,data属性目前只支持普通数组。如果需要使用其他特殊数据结构,例如immutable数组,请直接使用更底层的VirtualizedList组件。

extraData: any 

如果有除data以外的数据用在列表中(不论是用在renderItem还是Header或者Footer中),请在此属性中指定。同时此数据在修改时也需要先修改其引用地址(比如先复制到一个新的Object或者数组中),然后再修改其值,否则界面很可能不会刷新。

getItem: 

getItemCount: 

getItemLayout: (data: ?Array<ItemT>, index: number) => {length: number, offset: number, index: number} 

getItemLayout是一个可选的优化,用于避免动态测量内容尺寸的开销,不过前提是你可以提前知道内容的高度。如果你的行高是固定的,getItemLayout用起来就既高效又简单,类似下面这样:

getItemLayout = { (data , index )  = >  (  {length : 行高 , offset : 行高  * index , index }  ) }

注意如果你指定了SeparatorComponent,请把分隔线的尺寸也考虑到offset的计算之中。

horizontal?: ?boolean 

设置为true则变为水平布局模式。

initialNumToRender: number 

指定一开始渲染的元素数量,最好刚刚够填满一个屏幕,这样保证了用最短的时间给用户呈现可见的内容。注意这第一批次渲染的元素不会在滑动过程中被卸载,这样是为了保证用户执行返回顶部的操作时,不需要重新渲染首批元素。

keyExtractor: (item: ItemT, index: number) => string 

此函数用于为给定的item生成一个不重复的key。Key的作用是使React能够区分同类元素的不同个体,以便在刷新时能够确定其变化的位置,减少重新渲染的开销。若不指定此函数,则默认抽取item.key作为key值。若item.key也不存在,则使用数组下标。

legacyImplementation?: ?boolean 


设置为true则使用旧的ListView的实现。

numColumns: number 

多列布局只能在非水平模式下使用,即必须是horizontal={false}。此时组件内元素会从左到右从上到下按Z字形排列,类似启用了flexWrap的布局。组件内元素必须是等高的——暂时还无法支持瀑布流布局。

onEndReached?: ?(info: {distanceFromEnd: number}) => void 

当列表被滚动到距离内容最底部不足onEndReachedThreshold的距离时调用。

onEndReachedThreshold?: ?number 

决定当距离内容最底部还有多远时触发onEndReached回调。注意此参数是一个比值而非像素单位。比如,0.5表示距离内容最底部的距离为当前列表可见长度的一半时触发。

onRefresh?: ?() => void 

如果设置了此选项,则会在列表头部添加一个标准的RefreshControl控件,以便实现“下拉刷新”的功能。同时你需要正确设置refreshing属性。

onViewableItemsChanged?: ?(info: {viewableItems: Array<ViewToken>, changed: Array<ViewToken>}) => void 

在可见行元素变化时调用。可见范围和变化频率等参数的配置请设置viewabilityconfig属性

refreshing: ?boolean 

在等待加载新数据时将此属性设为true,列表就会显示出一个正在加载的符号。

renderItem: (info: {item: ItemT, index: number}) => ?React.Element<any> 

根据行数据data渲染每一行的组件。典型用法:

_renderItem  =  ( {item } )  = >  ( <TouchableOpacity onPress = { ( )  = >  this . _onPress(item ) } > <Text > {item .title } }< /Text ></TouchableOpacity >  ) ;  . . . <FlatList data = { [ {title :  'Title Text' , key :  'item1' } ] } renderItem = { this ._renderItem }  / >

data外还有第二个参数index可供使用。

viewabilityConfig: ViewabilityConfig 

请参考ViewabilityHelper的源码来了解具体的配置。

方法

scrollToEnd(params?: object) 

滚动到底部。如果不设置getItemLayout属性的话,可能会比较卡。

scrollToIndex(params: object) 

Scrolls to the item at a the specified index such that it is positioned in the viewable area such that viewPosition 0 places it at the top, 1 at the bottom, and 0.5 centered in the middle.

如果不设置getItemLayout属性的话,可能会比较卡。

scrollToItem(params: object) 

Requires linear scan through data - use scrollToIndex instead if possible. 如果不设置getItemLayout属性的话,可能会比较卡。

scrollToOffset(params: object) 

Scroll to a specific content pixel offset, like a normal ScrollView.

recordInteraction() 

Tells the list an interaction has occured, which should trigger viewability calculations, e.g. if waitForInteractions is true and the user has not scrolled. This is typically called by taps on items or by navigation actions.


特别注意:

onEndReached:在Android环境下是当滑动到距离底部(xx)距离时触发的,xx就是onEndReachedThreshold:x的设定值。已经滑动到底部后已经不满足距离底部xx的条件,不会再次触发onEndReached()事件的。

因为苹果的可滑动组件可以拉到底部之后让组件距离底部再拉伸一段距离,因此在苹果上可以将xx设置为负数,实现滑动到底部后上拉仍然触发onEndReached();

但是安卓上可滑动组件上拉倒底部之后不能再拉动,因此滑动到底部后再次上拉不会触发onEndReached()。

以下为一个小demo可以直接复制粘贴使用:


import  React, {Component} from 'react';
import {
    StyleSheet,
    View,
    FlatList,
    Text,
    Button,
    Dimensions,
    TouchableOpacity
} from 'react-native';
const { height, width } = Dimensions.get('window');
var ITEM_HEIGHT = 100;


export default class FlatListExample extends Component {

    constructor(props) {
        super(props);
        this.state = {
            refreshing: false
        };

    }
    _renderItem = (item) => {
        let item1 = item;
        var txt = '第' + item1.index + '个' + ' title=' + item1.item.title;
        var bgColor = item1.index % 2 == 0 ? 'red' : 'blue';
        return (
            <TouchableOpacity onPress={() => {
                alert(txt);
            } }>
                <Text style={[{ flex: 1, height: ITEM_HEIGHT, backgroundColor: bgColor, width: width / 2 }, styles.txt]}>{txt}</Text>
            </TouchableOpacity>
        )
    }

    _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' }}/>;
    }
    _onRefresh() {
        alert('正在刷新中.... ');
    }
    render() {
        var data = [];
        for (var i = 0; i < 31; i++) {
            data.push({ key: i, title: i + '' });
        }
        return (
            <View style={{ flex: 1 }}>
                <Button title='滚动到指定位置' onPress={() => {
                    //this._flatList.scrollToEnd();
                    //this._flatList.scrollToIndex({viewPosition:0,index:8});
                    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}


                        numColumns ={2}
                        columnWrapperStyle={{ borderWidth: 2, borderColor: 'black' }}
                        refreshing={this.state.refreshing}
                        getItemLayout={(data, index) => (
                            { length: ITEM_HEIGHT, offset: (ITEM_HEIGHT + 2) * index, index }
                        ) }
                        onRefresh={this._onRefresh}
                        onEndReachedThreshold={0.1}
                        onEndReached={(info) => {
                            alert("滑动到底部了");
                        } }

                        onViewableItemsChanged={(info) => {
                            //    alert("可见不可见触发");
                        } }
                        data={data}>
                    </FlatList>
                </View>


            </View>
        );
    }
}

const styles = StyleSheet.create({
    txt: {
        textAlign: 'center',
        textAlignVertical: 'center',
        color: 'white',
        fontSize: 30,
    }
});


module.exports = FlatListExample;


猜你喜欢

转载自blog.csdn.net/qq_34161388/article/details/72897292