ListHeaderComponent
属性用来给FlatList添加头部组件
简单使用:react
//ES6以前写法 _header = function () { return ( <Text style={{fontWeight: 'bold', fontSize: 20}}>热门电影</Text> ); } <FlatList ListHeaderComponent={this._header}//header头部组件 />
ListFooterComponent
属性为FlatList添加尾部组件,接收的参数跟ListHeaderComponent
相同。android
//ES6的写法 _footer = () => ( <Text style={{fontSize: 14, alignSelf: 'center'}}>到底啦,没有啦!</Text> ) <FlatList ListFooterComponent={this._footer} //添加尾部组件 />
添加头部和尾部组件比较简单,须要注意的就是上边二者ES5和6写法的区别!数组
ItemSeparatorComponent
属性能够为FlatList列表之间添加分割线。
举个例子:网络
class ItemDivideComponent extends Component { render() { return ( <View style={{height: 1, backgroundColor: 'skyblue'}}/> ); } }; <FlatList ItemSeparatorComponent={ItemDivideComponent}//分割线组件 />
这里咱们自定义了一个组件来设置分割线,固然咱们像添加头部和尾部同样,在内部声明以后使用this._header
的写法也是能够的!ide
ListEmptyComponent
属性,能够为FlatList设置一个没有数据的时候展现的视图!,这个属性能够接收的参数类型比较多,能够是React Component
,也能够是一个render函数
,或者渲染好的element
。
因此设置空数据视图不只能够像前边介绍的两种方式之外,还能够接收一个render函数
。
举个例子:函数
createEmptyView() { return ( <Text style={{fontSize: 40, alignSelf: 'center'}}>尚未数据哦!</Text> ); } <FlatList ListEmptyComponent={this.createEmptyView()} />
在前一篇博客中,咱们的设置data
的时候,是这样的:flex
data={[ {key: '大护法'}, {key: '绣春刀II:修罗战场'}, ... ]}
相似{key:你的数据value}
这样的形式,是由于咱们在设置data
的时候,必需要为item设置key
属性,不然会有一个黄色的警告弹出。并且咱们须要注意的是这里每个item的key
是惟一的!,若是按照这样的写法,咱们在数据中有重复的,好比{key: '大护法'},{key: '大护法'}
,这里的大护法
只会显示一个,由于FlatList会认为这是一条数据,由于key
相同!
那么为何会这样?
由于FlatList中有一个属性:keyExtractor
,用于为给定的item生成一个不重复的key。若不指定此函数,则默认抽取item.key做为key值。若item.key也不存在,则使用数组下标index。由于前边没有指定该属性,因此就把item.key
做为了key值,才会认定两个重复的数据是一条数据!优化
那么通常地,咱们能够这样使用:this
_keyExtractor = (item, index) => index; <FlatList keyExtractor={this._keyExtractor} />
这样就把data
中数组的下标做为了惟一的key
。
那么在data
中指定数据的时候,就不用{key: '大护法'}
这样写了,由于咱们已经指定了惟一的key,而能够随意写{name: '大护法'}
或者{movie: '大护法'}
,在渲染item的时候,取值用item.name
或者item.movie
便可!也不会有黄色的警告出现!spa
你明白了吗?
getItemLayout
属性是一个可选的优化,用于避免动态测量内容尺寸的开销。若是咱们知道item的高度,就能够为FlatList指定这一个属性,来使FlatList更加高效的运行!
举个例子:
getItemLayout={(data, index) => ({ length: 44, offset: (44 + 1) * index, index })}
咱们在上边使用的时候指定了item的高度为44,因此length
参数为44;咱们设置了分割线,且指定分割线的高度是1,因此offset
参数为44+1。综合来看,设置这个属性应这样写:
getItemLayout={(data, index) => ({ length: 你的item的height, offset: (你的item的height + ItemSeparator的height) * index, index })}
设置这一属性,在调用FlatList的跳转函数的时候很是有用,不然可能会很卡顿!如scrollToEnd()
,scrollToIndex()
,这两个方法后边再说!
FlatList中有两个属性,能够用来设置下拉刷新。
refreshing
在等待加载新数据时将此属性设为true,列表就会显示出一个正在加载的符号.onRefresh
若是设置了此选项,则会在列表头部添加一个标准的RefreshControl
控件,以便实现“下拉刷新”的功能。同时你须要正确设置refreshing
属性。这里的RefreshControl
控件,很是相似于Android v4包中的SwipeRefreshLayout
,这里就很少说了,须要了解的能够查看相关文档!
如何使用,举个例子:
refreshing={this.state.refreshing} onRefresh={() => { this.setState({refreshing: true})//开始刷新 //这里模拟请求网络,拿到数据,3s后中止刷新 setTimeout(() => { alert('没有可刷新的内容!'); this.setState({refreshing: false});//中止刷新 }, 3000); }}
关于上拉加载,FlatList也封装有两个属性来实现:
onEndReachedThreshold
:这个属性决定当距离内容最底部还有多远时触发onEndReached回调。须要注意的是此参数是一个比值而非像素单位。好比,0.5表示距离内容最底部的距离为当前列表可见长度的一半时触发。因此它的取值范围为:(0,1),不包含0和1。onEndReached
:列表被滚动到距离内容最底部不足onEndReachedThreshold设置的的距离时调用。具体使用,举个例子:
onEndReachedThreshold={0.1} onEndReached={({distanceFromEnd}) => ( setTimeout(() => { this.setState((state) => ({ data: state.data.concat(this._newData), })); }, 3000) )}
这里咱们设置的距离为列表可见长度的1/10,而触发了onEndReached函数时,咱们设置了一个定时器,3s后,将data
中的数据添加了新数据,从而达到上拉加载更多的效果!
FlatList下有两个比较经常使用的函数:
scrollToEnd() 滚动到底部。若是不设置getItemLayout属性的话,可能会比较卡。
scrollToIndex()若是不设置getItemLayout属性的话,没法跳转到当前可视区域之外的位置。
如官方所言,使用这两个函数的时候,最好指定设置getItemLayout
属性。
由于这两个是FlatList组件的函数,因此在使用这两个函数以前,首先咱们要获得FlatList组件的引用。
这时候就须要ref
属性。react提供的这个ref
属性,表示为对组件真正实例的引用。
关于ref
属性的使用,能够去React官网查看API!
具体的使用:
ref={(flatList) => this._flatList = flatList} this._flatList.scrollToEnd(); //viewPosition参数:0表示顶部,0.5表示中部,1表示底部 this._flatList.scrollToIndex({viewPosition: 0, index: this.state.text});
至此,关于FlatList进阶的相关基础内容就说完了!
class FlatListTest extends Component { constructor(props) { super(props); this.state = { data: this._sourceData, refreshing: false, //初始化不刷新 text: ''//跳转的行 }; } _header = function () { return ( <Text style={{fontWeight: 'bold', fontSize: 20}}>热门电影</Text> ); } _footer = () => ( <Text style={{fontSize: 14, alignSelf: 'center'}}>到底啦,没有啦!</Text> ) createEmptyView() { return ( <Text style={{fontSize: 40, alignSelf: 'center'}}>尚未数据哦!</Text> ); } //此函数用于为给定的item生成一个不重复的key //若不指定此函数,则默认抽取item.key做为key值。若item.key也不存在,则使用数组下标index。 _keyExtractor = (item, index) => index; itemClick(item, index) { alert('点击了第' + index + '项,电影名称为:' + item.name); } _renderItem = ({item, index}) => { return ( <TouchableOpacity activeOpacity={0.5} onPress={this.itemClick.bind(this, item, index)}> <Text style={flatListStyles.item}>{item.name}</Text> </TouchableOpacity> ); } //点击按钮跳转 onButtonPress() { //viewPosition参数:0表示顶部,0.5表示中部,1表示底部 this._flatList.scrollToIndex({viewPosition: 0, index: this.state.text}); //this._flatList.scrollToOffset({ animated: true, offset: 2000 }); }; onBtnPress2Botton() { this._flatList.scrollToEnd(); } _sourceData = [ {name: '大护法'}, {name: '绣春刀II:修罗战场'}, {name: '神偷奶爸3'}, {name: '神奇女侠'}, {name: '摔跤吧,爸爸'}, {name: '悟空传'}, {name: '闪光少女'}, {name: '攻壳机动队'}, {name: '速度与激情8'}, {name: '蝙蝠侠大战超人'}, {name: '攻壳机动队'}, {name: '速度与激情8'}, {name: '蝙蝠侠大战超人'} ] _newData = [{name: '我是新添加的数据1'}, {name: '我是新添加的数据2'}, {name: '我是新添加的数据3'}] render() { return ( <View style={flatListStyles.container}> <View style={{flexDirection: 'row', justifyContent: 'center', alignItems: 'center'}}> <TextInput style={{flex: 1}} placeholder="请输入要跳转的行号" onChangeText={(text) => this.setState({text})} /> <Button title="跳转到行" onPress={this.onButtonPress.bind(this)} color={'skyblue'}/> <Button title="跳转到底部" onPress={this.onBtnPress2Botton.bind(this)} color={'green'}/> </View> <FlatList data={this.state.data} //使用 ref 能够获取到相应的组件 ref={(flatList) => this._flatList = flatList} ListHeaderComponent={this._header}//header头部组件 ListFooterComponent={this._footer}//footer尾部组件 ItemSeparatorComponent={ItemDivideComponent}//分割线组件 //空数据视图,能够是React Component,也能够是一个render函数,或者渲染好的element。 ListEmptyComponent={this.createEmptyView()} keyExtractor={this._keyExtractor} //是一个可选的优化,用于避免动态测量内容尺寸的开销,不过前提是你能够提早知道内容的高度。 //若是你的行高是固定的,getItemLayout用起来就既高效又简单. //注意若是你指定了SeparatorComponent,请把分隔线的尺寸也考虑到offset的计算之中 getItemLayout={(data, index) => ( {length: 44, offset: (44 + 1) * index, index} )} //决定当距离内容最底部还有多远时触发onEndReached回调。 //注意此参数是一个比值而非像素单位。好比,0.5表示距离内容最底部的距离为当前列表可见长度的一半时触发。 onEndReachedThreshold={0.1} //当列表被滚动到距离内容最底部不足onEndReachedThreshold的距离时调用 onEndReached={({distanceFromEnd}) => ( setTimeout(() => { this.setState((state) => ({ data: state.data.concat(this._newData), })); }, 3000) )} refreshing={this.state.refreshing} onRefresh={() => { this.setState({refreshing: true})//开始刷新 //这里模拟请求网络,拿到数据,3s后中止刷新 setTimeout(() => { alert('没有可刷新的内容!'); this.setState({refreshing: false}); }, 3000); }} renderItem={this._renderItem} /> </View> ); } } ; class ItemDivideComponent extends Component { render() { return ( <View style={{height: 1, backgroundColor: 'skyblue'}}/> ); } } ; const flatListStyles = StyleSheet.create({ container: { flex: 1, paddingTop: 22 }, item: { padding: 10, fontSize: 18, height: 44, }, }) AppRegistry.registerComponent('AwesomeProject', () => FlatListTest);