《React-Native系列》19、 ListView组件之上拉刷新(iOS和Android通用)
2016-12-18 17:06
1371 查看
ReactNative提供了RefreshControl下拉刷新组件,但是没有提供上拉刷新组件,上拉刷新在App中是很常用的。
今天我们来实现一个iOS和Android通用的上拉刷新功能。
下面简要介绍下我实现的思路。
如果你对ListView的基础知识不是很清楚,建议先移步:《React-Native系列》16、 RN组件之ListView
思路:
plain copy
const moreText = "加载完毕"; //foot显示的文案
//页码
var pageNum = 1;
//每页显示数据的条数
const pageSize = 10;
//页面总数据数
var pageCount = 0;
//页面List总数据
var totalList = new Array();
//foot: 0 隐藏 1 已加载完成 2 显示加载中
plain copy
<ListView
enableEmptySections={true}
dataSource={this.state.dataSource}
renderRow={this._renderRow.bind(this)}
renderFooter={this._renderFooter.bind(this)}
onEndReached={this._endReached.bind(this)}
onEndReachedThreshold={0}
/>
[javascript] view
plain copy
constructor(props) {
super(props);
this.state = {
dataSource: new ListView.DataSource({
rowHasChanged: (r1, r2) => r1 !== r2,
}),
loaded: false,//控制Request请求是否加载完毕
foot:0,// 控制foot, 0:隐藏foot 1:已加载完成 2 :显示加载中
error:false,
这里我们主要声明了dataSource,这个没什么说的
loaded:用来控制整个页面的菊花
error:如果Request错误,显示一个错误页面
foot: 控制Footer的view
plain copy
componentWillMount() {
this._fetchListData();
}
plain copy
_fetchListData() {
if(pageNum > 1){
this.setState({loaded:true});
}
fetch(requestURL, {
method: 'get',
headers: headerObj,
}).then(response =>{
if (response.ok) {
return response.json();
} else {
this.setState({error:true,loaded:true});
}
}).then(json=>{
let responseCode = json.code;
if (responseCode == 0) {
let responseData = json.data;
pageCount = responseData.count;
let list = responseData.data;
if (orderList == null) {
orderList = [];
currentCount = 0;
} else {
currentCount = list.length;
}
if(currentCount < pageSize){
//当当前返回的数据小于PageSize时,认为已加载完毕
this.setState({ foot:1,moreText:moreText});
}else{//设置foot 隐藏Footer
this.setState({foot:0});
}
for (var i=0; i < list.length; i++) {
totalList.push( list[i] );
}
this.setState({
dataSource: this.state.dataSource.cloneWithRows(totalList),
loaded: true,
});
}else{
this.setState({error:true,loaded:true});
}
}).catch(function (error) {
this.setState({error:true,loaded:true});
});
}
这里的细节挺多的:
1、当pageNum > 1时,就不要整个页面的菊花,此时loaded一直为true,这个主要是为了页面效果,要不然没加载一页数据,这个屏幕就会闪一下。
2、比较当前返回的list的大小,是否小于pageSize,控制Footer是否隐藏,还是显示已加载完毕
3、声明了一个全局的totalList对象,每次有新数据的时候,都push进去。
如果不采用push的方式的话,直接采用setState方法的话,第二页会把第一页的数据覆盖掉。
[javascript] view
plain copy
_renderFooter() {
if(this.state.foot === 1){//加载完毕
return (
<View style={{height:40,alignItems:'center',justifyContent:'flex-start',}}>
<Text style={{color:'#999999',fontSize:12,marginTop:10}}>
{this.state.moreText}
</Text>
</View>);
}else if(this.state.foot === 2) {//加载中
return (
<View style={{height:40,alignItems:'center',justifyContent:'center',}}>
<Image source={{uri:loadgif}} style={{width:20,height:20}}/>
</View>);
}
}
根据状态机变量foot控制Footer的显示
当所有的数据都已经渲染过,并且列表被滚动到距离最底部不足onEndReachedThreshold个像素的距离时调用。原生的滚动事件会被作为参数传递。译注:当第一次渲染时,如果数据不足一屏(比如初始值是空的),这个事件也会被触发
[javascript] view
plain copy
_endReached(){
if(this.state.foot != 0 ){
return ;
}
this.setState({
foot:2,
});
this.timer = setTimeout(
() => {
pageNum ++;
this._fetchListData();
},500);
}
这里需要注意一下几点
1、第一屏的时候可能也会触发_endReached方法,所以需要判断foot为非 0(即加载中和已加载完毕)时,直接return
2、上拉时,触发_endReached方法,可能server端接口响应很快,几乎看不到菊花效果,特地加了个500毫秒的等待
plain copy
componentWillUnmount() {
// 如果存在this.timer,则使用clearTimeout清空。
// 如果你使用多个timer,那么用多个变量,或者用个数组来保存引用,然后逐个clear
this.timer && clearTimeout(this.timer);
}
待优化点:
1、如果ListView的翻页较多的话,全局变量totalList会非常大,对内存是考验。
如果有问题疑问,可以留言交流。
今天我们来实现一个iOS和Android通用的上拉刷新功能。
下面简要介绍下我实现的思路。
如果你对ListView的基础知识不是很清楚,建议先移步:《React-Native系列》16、 RN组件之ListView
思路:
1、常量定义:
[javascript] viewplain copy
const moreText = "加载完毕"; //foot显示的文案
//页码
var pageNum = 1;
//每页显示数据的条数
const pageSize = 10;
//页面总数据数
var pageCount = 0;
//页面List总数据
var totalList = new Array();
//foot: 0 隐藏 1 已加载完成 2 显示加载中
2、定义ListView
[javascript] viewplain copy
<ListView
enableEmptySections={true}
dataSource={this.state.dataSource}
renderRow={this._renderRow.bind(this)}
renderFooter={this._renderFooter.bind(this)}
onEndReached={this._endReached.bind(this)}
onEndReachedThreshold={0}
/>
3、声明State状态机变量
ListView.DataSource实例(列表依赖的数据源)[javascript] view
plain copy
constructor(props) {
super(props);
this.state = {
dataSource: new ListView.DataSource({
rowHasChanged: (r1, r2) => r1 !== r2,
}),
loaded: false,//控制Request请求是否加载完毕
foot:0,// 控制foot, 0:隐藏foot 1:已加载完成 2 :显示加载中
error:false,
这里我们主要声明了dataSource,这个没什么说的
loaded:用来控制整个页面的菊花
error:如果Request错误,显示一个错误页面
foot: 控制Footer的view
4、渲染页面前,加载数据
[javascript] viewplain copy
componentWillMount() {
this._fetchListData();
}
5、Load服务端数据
[javascript] viewplain copy
_fetchListData() {
if(pageNum > 1){
this.setState({loaded:true});
}
fetch(requestURL, {
method: 'get',
headers: headerObj,
}).then(response =>{
if (response.ok) {
return response.json();
} else {
this.setState({error:true,loaded:true});
}
}).then(json=>{
let responseCode = json.code;
if (responseCode == 0) {
let responseData = json.data;
pageCount = responseData.count;
let list = responseData.data;
if (orderList == null) {
orderList = [];
currentCount = 0;
} else {
currentCount = list.length;
}
if(currentCount < pageSize){
//当当前返回的数据小于PageSize时,认为已加载完毕
this.setState({ foot:1,moreText:moreText});
}else{//设置foot 隐藏Footer
this.setState({foot:0});
}
for (var i=0; i < list.length; i++) {
totalList.push( list[i] );
}
this.setState({
dataSource: this.state.dataSource.cloneWithRows(totalList),
loaded: true,
});
}else{
this.setState({error:true,loaded:true});
}
}).catch(function (error) {
this.setState({error:true,loaded:true});
});
}
这里的细节挺多的:
1、当pageNum > 1时,就不要整个页面的菊花,此时loaded一直为true,这个主要是为了页面效果,要不然没加载一页数据,这个屏幕就会闪一下。
2、比较当前返回的list的大小,是否小于pageSize,控制Footer是否隐藏,还是显示已加载完毕
3、声明了一个全局的totalList对象,每次有新数据的时候,都push进去。
如果不采用push的方式的话,直接采用setState方法的话,第二页会把第一页的数据覆盖掉。
6、定义renderRow方法
renderRow={this._renderRow.bind(this)} 列表组件渲染函数 ,此处页面逻辑省略。7、定义renderFooter方法
renderFooter 页脚会在每次渲染过程中都重新渲染。[javascript] view
plain copy
_renderFooter() {
if(this.state.foot === 1){//加载完毕
return (
<View style={{height:40,alignItems:'center',justifyContent:'flex-start',}}>
<Text style={{color:'#999999',fontSize:12,marginTop:10}}>
{this.state.moreText}
</Text>
</View>);
}else if(this.state.foot === 2) {//加载中
return (
<View style={{height:40,alignItems:'center',justifyContent:'center',}}>
<Image source={{uri:loadgif}} style={{width:20,height:20}}/>
</View>);
}
}
根据状态机变量foot控制Footer的显示
8、onEndReached 定义
onEndReachedThreshold={0}当所有的数据都已经渲染过,并且列表被滚动到距离最底部不足onEndReachedThreshold个像素的距离时调用。原生的滚动事件会被作为参数传递。译注:当第一次渲染时,如果数据不足一屏(比如初始值是空的),这个事件也会被触发
[javascript] view
plain copy
_endReached(){
if(this.state.foot != 0 ){
return ;
}
this.setState({
foot:2,
});
this.timer = setTimeout(
() => {
pageNum ++;
this._fetchListData();
},500);
}
这里需要注意一下几点
1、第一屏的时候可能也会触发_endReached方法,所以需要判断foot为非 0(即加载中和已加载完毕)时,直接return
2、上拉时,触发_endReached方法,可能server端接口响应很快,几乎看不到菊花效果,特地加了个500毫秒的等待
9、卸载Timer
[javascript] viewplain copy
componentWillUnmount() {
// 如果存在this.timer,则使用clearTimeout清空。
// 如果你使用多个timer,那么用多个变量,或者用个数组来保存引用,然后逐个clear
this.timer && clearTimeout(this.timer);
}
待优化点:
1、如果ListView的翻页较多的话,全局变量totalList会非常大,对内存是考验。
如果有问题疑问,可以留言交流。
相关文章推荐
- React-Native实现ListView组件之上拉刷新实例(iOS和Android通用)
- 《React-Native系列》19、 ListView组件之上拉刷新(iOS和Android通用)
- 《React-Native系列》13、 组件封装之Dialog(iOS和Android通用)
- 《React-Native系列》组件封装之Dialog(iOS和Android通用)
- 《React-Native系列》23、 js实现下拉刷新效果(Android和iOS通用)
- 支持android&ios高度自适应及JS相互调用的组件react-native-webview2
- react-native-scrolltotop 回到顶部-组件 (ios/android)
- React Native之Image组件使用时Android和iOS兼容性
- react-native-easy-toast, 一款简单易用的 Toast 组件,支持 Android&iOS.
- 《React-Native系列》16、 RN组件之ListView
- 【React Native开发】React Native控件之ListView组件解说以及最齐全实例(19)
- react-native-smart-barcode目前最好用的二维码扫描组件(IOS、android)
- 【Android】通用系列 —— 下拉刷新之继承ListView的下拉刷新
- React-Native系列Android——自定义View组件开发
- 【React Native开发】React Native 控件之Modal详解-Android/iOS双平台通用(56)
- react-native-easy-toast, 一款简单易用的 Toast 组件,支持 Android&iOS.
- ReactNative实战系列 组件封装之Dialog(iOS和Android通用)
- 《React-Native系列》16、 RN组件之ListView
- react-native-easy-toast, 一款简单易用的 Toast 组件,支持 Android&iOS.
- react-native-smart-barcode目前最好用的二维码扫描组件(IOS、android)