FlatList基本用法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
import React from 'react';
import {SafeAreaView, View, FlatList, StyleSheet, Text, StatusBar} from 'react-native';
const DATA = [
{
id: 'bd7acbea-c1b1-46c2-aed5-3ad53abb28ba',
title: 'First Item',
},
{
id: '3ac68afc-c605-48d3-a4f8-fbd91aa97f63',
title: 'Second Item',
},
{
id: '58694a0f-3da1-471f-bd96-145571e29d72',
title: 'Third Item',
},
];
const Item = ({title})=>(
<View style={styles.item}>
<Text style={styles.title}>{title}</Text>
</View>
)
const App = ()=>{
const renderItem = ({item})=>(
<Item title={item.title}></Item>
)
return (
<SafeAreaView style={styles.container}>
<FlatList
data={DATA}
renderItem={renderItem}
keyExtractor={item=>item.id}>
</FlatList>
<FlatList
data={[{ title: 'Title Text', key: 'item1' }]}
renderItem={({item, index, separators})=>(
<TouchableHightlight
onPress={()=>this._onPress(item)}
onShowUnderlay={separators.hightlight}
onHideUnderlay={separators.unhightlight}
<View style={{backgroundColor:'white'}}>
<Text>{item.title}</Text>
</View>
>
</TouchableHightlight>
)}
/>
</SafeAreaView>
)
}
const styles = StyleSheet.create({
container:{
flex: 1,
marginTop: StatusBar.currentHeight || 0,
},
item: {
backgroundColor: '#f92cff',
padding: 20,
marginVertical: 8,
marginHorizontal: 16,
},
title: {
fontSize: 32,
},
})

StyleSheet中CSS属性遵循驼峰命名法

FlatList下拉刷新

​ FlatList有onRefresh属性,如果设置了此选项,就会在列表头部添加一个标准的RefreshControl控件,以便实现下拉刷新的功能。onRefresh是一个方法。

​ FlatList有refreshing属性,在等待加载新数据时,将此属性设为true,列表就会显示出一个正在加载的符号。refreshing需要一个bool值。

FlatList上拉加载

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

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

ListFooterComponent属性,尾部组件。

FlatList下拉刷新上拉加载步骤

  • 创建RefreshState.js存放上拉加载的状态 (五个状态)
1
2
3
4
5
6
7
8
// RefreshState.js 这些状态是通过当前向服务器请求新数据后修改所得的
export default {
Idle: 'Idle', // 初始状态,无刷新的情况
CanLoadMore: 'CanLoadMore', // 可以加载更多,表示列表还有数据可以继续加载
Refreshing: 'Refreshing', // 正在刷新中
NoMoreData: 'NoMoreData', // 没有更多数据了,可以根据当前获取到的item条数和服务器传过来的数据总条数count对比可得是否还有更多的数据
Failure: 'Failure' // 刷新失败
}
  • 封装RefreshFooter组件,根据不同的状态,在列表尾部显示不同的文字信息
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
import React, {Component} from 'react';
import {View, Text, ActivityIndicator, StyleSheet, TouchableOpacity} from 'react-native';
import RefreshState from './RefreshState';
import PropTypes from 'prop-types';

export default class RefreshFooter extends Component{
static propTypes = {
onLoadMore: PropTypes.func,
onRetryLoading: PropTypes.func
};
static defaultProps = {
footerRefreshingText: "努力加载中",
footerLoadMoreText: "上拉加载更多",
footerFailureText: "点击重新加载",
footerNoMoreDataText: "已全部加载完毕"
};
render(){
let {state} = this.props;
let footer = null;
switch(state){
case RefreshState.Idle:
// Idle情况下为null,不显示尾部组件
break;
case RefreshState.Refreshing:
footer =
<View style={styles.loadingView}>
<ActivityIndicator size="small"/>
<Text style={styles.refreshingText}>{this.props.footerRefreshingText}</Text>
</View>
break;
case RefreshState.CanLoadMore:
footer =
<View style={styles.loadingView}>
<Text style={styles.footerText}>{this.props.footerLoadMoreText}</Text>
</View>
break;
case RefreshState.NoMoreData:
footer =
<View style={styles.loadingView}>
<Text style={styles.footerText}>{this.props.footerNoMoreDataText}</Text>
</View>
break;
case RefreshState.Failure:
// 加载失败的情况下,调用外部的onRetryLoading重新加载数据
footer =
<TouchableOpacity style={styles.loadingView} onPress={()=>{
this.props.onRetryLoading&&this.props.onRetryLoading();
}}>
<Text style={styles.footerText}>{this.props.footerFailureText}</Text>
</TouchableOpacity>
break;
}
return footer;
}
}
const styles = StyleSheet.create({
loadingView: {
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
padding: 15
},
refreshingText: {
fontSize: 12,
color: '#666666',
paddingLeft: 10
},
footerText: {
fontSize: 12,
color: '#666666'
}
})
  • 实现带有上拉加载和下拉刷新的RefreshListView,具体调用数据的方法应该在外部实现

  • 先定义上拉加载和下拉刷新的方法

1
2
3
4
static propTypes = {
onHeaderRefresh: PropTypes.func,
onFooterRefresh: PropTypes.func
}
  • 定义bool值isHeaderRefreshing作为refreshing属性的值,控制头部显示与否。定义bool值isFooterRefreshing来判断尾部组件的刷新状态。定义footerState用来设定当前尾部组件的state,作为RefreshFooter的值。
1
2
3
4
5
6
7
8
constructor(props) {
super(props);
this.state = {
isHeaderRefreshing: false, // 头部是否正在刷新
isFooterRefreshing: false, // 尾部是否正在刷新
footerState: RefreshState.Idle, // 尾部当前的状态,默认为Idle
}
}
  • render函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
render(){
return (
<FlatList
{...this.props}
onRefresh={()=>{this.beginHeaderRefresh()}}
refreshing={this.state.isHeaderRefreshing}
onEndReached={()=>{this.beginFooterRefresh()}}
onEndReachedThreshold={0.1}
ListFooterComponent={this._renderFooter}
>
</FlatList>
)
_renderFooter = ()=>{
return (
<RefreshFooter
state={this.state.footerState}
onRetryLoading={()=>{this.beginFooterRefresh()}}
/>
)
}
}
  • beginHeaderRefresh和beginFooterRefresh两个方法用来调用刷新的,但是刷新之前还需要做逻辑处理。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
// 下拉刷新
beginHeaderRefresh(){
if(this.shouldStartHeaderRefreshing()){
this.startHeaderRefreshing();
}
}
// 上拉加载
beginFooterRefresh(){
if(this.shouldStartFooterRefreshing()){
this.startFooterRefreshing();
}
}
// 是否头部应该刷新
shouldStartHeaderRefreshing(){
if(this.state.footerState===RefreshState.Refreshing||
this.state.isHeaderRefreshing||
this.state.isFooterRefreshing)
return false;
return true;
}
// 是否尾部应该加载
shouldStartFooterRefreshing(){
if(this.state.footerState===RefreshState.Refreshing||
this.state.footerState===RefreshState.NoMoreData||
this.props.data.length===0||
this.state.isHeaderRefreshing||
this.state.isFooterRefreshing)
return false;
return true;
}
startHeaderRefreshing(){
this.setState({
isHeaderRefreshing: true
},
()=>{
this.props.onHeaderRefresh&&this.props.onHeaderRefresh();
})
}
startFooterRefreshing(){
this.setState({
isFooterRefreshing: true,
footerState: RefreshState.Refreshing
},
()=>{
this.props.onFooterRefresh&&this.props.onFooterRefresh()
})
}
  • 刷新完毕后通过修改状态来停止刷新
1
2
3
4
5
6
7
8
9
10
endRefreshing(footerState){
let footerRefreshState = footerState;
if(this.props.data.length===0)
footerRefreshState = RefreshState.Idle;
this.setState({
footerState: footerRefreshState,
isHeaderRefreshing: false,
isFooterRefreshing: false
})
}
  • 定义父组件中数据获取方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
loadData(){
let that = this;
fetch(queryData('beijing', this.state.startPage, this.state.pageSize).then(res=>{
let res1 = res.data;
let totalCount = res.total;
let currentCount = this.state.data.length;
let footerState = RefreshState.Idle;
let startPage = this.state.startPage;
if(currentCount+res1<totalCount){
footerState=RefreshState.CanLoadMore;
startPage += 1;
}else
footerState=RefreshState.NoMoreData;
this.setState({data: [...data, res1], startPage});
this.listView.endRefreshing(footerState);
})).catch(e=>{
that.listView.endRefreshing(RefreshState.Failure);
})
}

总结

​ 定义尾组件的状态**—–>封装RefreshFooter尾组件—–>通过onRefresh(方法)、refreshing(bool)、onEndReached、onEndReachedThreshold、ListFooterComponent封装RefreshListView组件,在该组件中定义三个状态,分别用于表示头组件、尾组件是否在刷新、尾组件当前状态,定义方法来判断头组件和尾组件是否需要执行更新,如果需要则调用父组件中传入的数据更新方法,更新完毕后修改组件状态来结束更新—->**在父组件中调用RefreshListView组件同时定义获取数据的方式