上一篇博客介绍了ScrollableTabView组件,其中封装了一个CategoryList组件,这篇博客介绍一下这个组件的封装,其实看下图很简单的,就是一个FlatList组件,但还是第一次使用还是出现了很多问题。
render() {
return (
<FlatList
numColumns={4}
style={styles.container}
data={this.state.data}
keyExtractor={(info) => info.index}
initialNumToRender={24}
getItemLayout={(data, index) => (
{length: ScreenHelper.scale(315), offset: ScreenHelper.scale(315) * index, index}
)}
renderItem={this.renderItem.bind(this)}
ListFooterComponent={this._renderFooter.bind(this)}
onEndReached={this._onEndReached.bind(this)}
onEndReachedThreshold={0.5}
ItemSeparatorComponent={this._separator}/>
);
}
这是一个FlatList组件,用于渲染如上图所示的页面
numColumns={num} //可以设置一行渲染几个,比如我这里设置num=4,就是一行渲染四个。
data={this.state.data} //设置数据源,FlatList的数据源是一个简单的Array
initialNumToRender={24} //初始渲染几个,这里设置为我一次请求的数据量24,因为进行了分页加载。
//getItemLayout是一个可选的优化,用于避免动态测量内容尺寸的开销,不过前提是你可以提前知道内容的高度。如果你的行高是固定的,getItemLayout用起来就既高效又简单。
(data, index) => {length: number, offset: number, index: number}
getItemLayout={(data, index) => (
{length: ITEM_HEIGHT, offset: ITEM_HEIGHT * index, index}
)}
//对于元素较多的列表(几百行)来说,添加getItemLayout可以极大地提高性能。注意如果你指定了ItemSeparatorComponent,请把分隔线的尺寸也考虑到 offset 的计算之中。
getItemLayout={(data, index) => (
{length: ScreenHelper.scale(315), offset: ScreenHelper.scale(315) * index, index}
)}
renderItem={this.renderItem.bind(this)} //渲染每一个Item的方法
ItemSeparatorComponent={this._separator()}/> //渲染分割线的方法
_separator = () => {
return (<View style={{height: ScreenHelper.scale(10)}}/>);
};
在渲染分割线的时候,我出现了一个错误,就是this._separator()加上了括号,这样会爆出来一个错误:
这样是因为,你加上括号返回的就不是分割线这个布局了,而是返回了一串字符串对象,所以 此处应该是
ItemSeparatorComponent={this._separator}/>
这里我进行了分页加载,所以还有三个方法:
ListFooterComponent={this._renderFooter.bind(this)}//当每一页结束时FlatList渲染的尾部布局
onEndReached={this._onEndReached.bind(this)} //当列表被滚动到距离内容最底部不足onEndReachedThreshold的距离时调用。
onEndReachedThreshold={0.5} //决定当距离内容最底部还有多远时触发onEndReached回调。此参数是一个比值而非像素单位。比如,0.5 表示距离内容最底部的距离为当前列表可见长度的一半时触发。
_renderFooter(){
if (this.state.showFoot === 1) {
return (
<View style={{height:30,alignItems:'center',justifyContent:'flex-start',}}>
<Text style={{color:'#999999',fontSize:14,marginTop:5,marginBottom:5,}}>
没有更多数据了
</Text>
</View>
);
} else if(this.state.showFoot === 2) {
return (
<View style={styles.footer}>
<ActivityIndicator />
<Text>正在加载更多数据...</Text>
</View>
);
} else if(this.state.showFoot === 0){
return (
<View style={styles.footer}>
<Text></Text>
</View>
);
}
}
_onEndReached(){
//如果是正在加载中或没有更多数据了,则返回
if(this.state.showFoot !== 0 ){
return ;
}
//如果当前页大于或等于总页数,那就是到最后一页了,返回
if((this.state.pageNo!==1) && (this.state.showFoot===1)){
return;
} else {
console.log(this.state.pageNo);
}
//底部显示正在加载更多数据
this.setState({showFoot:2});
//获取数据
this.fetchData();
}
//数据请求方法以及数据处理
fetchData() {
let dataSource=null;//
let dataBlob = []; //
let params = {
"classification": this.classification,
"category": this.category,
"pageNo": this.state.pageNo,
"pageSize": 24,
};//此处是POST请求方法,故设置请求参数
let options = {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json"
},
body: JSON.stringify(params),
};
fetch('http://27.223.99.143:11181/read/read/xxx', options)
.then(response => {
if (response.ok) {
return response.json();
} else {
this.setState({
isLoading: false,
error: true
})
}
})
.then(responseJson => {
if (responseJson.err_no === '200') {
dataSource=responseJson.SST.list;//将数据设置到一个数组中
let i = 0;
dataSource.map(function (item) {
dataBlob.push(item);
i++;
});//对数据进行遍历,将数据加入到一个dataBlob钟
let foot = 0;
if(i<24){
foot = 1;//listView底部显示没有更多数据了
}
this.setState({
//每次加载更多数据时,复制数据,改变state中的data数据源
data:this.state.data.concat(dataBlob),
isLoading: true,
showFoot:foot,
pageNo:this.state.pageNo+1,//pageNo+1,下次请求数据的参数设置
});
dataSource = null;
dataBlob = null;
} else {
this.setState({
isLoading: false,
error: true,
})
}
})
.catch(err => {
//todo 设置error状态,结束loading状态
this.setState({
isLoading: false,
error: true,
})
}).done();
}
二十来天,从没有接触过,到做出来一个小的功能模块,虽然有很多东西参考别人做的,模块还存在很多问题,但在这个过程中,自己学会了很多东西。