React-Native|实现ListView下拉刷新加载更多

ListView是android中使用频率非常高的控件,在React-Native中也是如此。
翻阅了关于ListView的一些介绍和博客,我自己也总结了一下。

使用ListView的步骤,最开始是初始化ListView.DataSource,在构造它时指定更新策略。有两种策略,分别为rowHasChangedsectionHeaderHasChanged
顾名思义就是表示行变化和sectionHeader变化时行,就会进行更新。
我简单的理解:
如果你的ListView数据源是纯数组,那么不需要设置sectionHeaderHasChanged,如果数据源有是键值对,需要定义。

另外就是cloneWithRows和cloneWithRowsAndSections,为数据源赋予数据。
另外注意的是,如果你之前的dataSource有值,然后进行clone操作,那么会覆盖之前的值,clone操作会重新生成一个数据源。

经过对ListView的简单研究,我写了一个上拉刷新,加载更多的ListView的例子。源码如下:

import ListViewItemDemo from './ListViewItemDemo';
import Toast,{DURATION} from 'react-native-easy-toast';
const URL="http://101.201.78.24/api//activity/list";
let pn=1;
let maxResults=10;
const PageSize="&maxResults="+maxResults;

export default class ListViewDemo extends Component {

    constructor(props){
        super(props);
        this.state={
            count:0,
            result:'',
            refreshing:true,
            dataSource:new ListView.DataSource({
                rowHasChanged:(r1,r2)=>r1!=r2,
            }),
            isFirstIn:true,
            dataArray:[],
        };
    }


    getPromise(url){
        var promise=new Promise((resolve,reject)=>{
            fetch(url).then(response=> response.json()).
            then(result=>resolve(result)).
            catch(error=>reject(error));
        });
        return promise;
    }



    /*
        网络加载是异步的,需要结合Promise来进行回调。
        fetch(URL)resolve返回的数据是response对象
        response.json(),解析一个字符串,构建一个对象或值。相当于JSON.parse()
        JSON.stringify,从一个对象中解析出字符串
    */
    componentDidMount(){
        this.setState({
            refreshing:true,
        });
        let url=URL+"?pn="+pn+PageSize;
        this.getPromise(url).then(result=> {
            this.setState({
                    dataSource: this.state.dataSource.cloneWithRows(result.data.results),
                    refreshing:false,
                    dataArray:result.data.results,
                })
            }
        ).catch(error=>{
            console.log(error)
        });
    }

    renderRow(item){
        return <ListViewItemDemo item={item}/>
    }

    renderLine(){
        return <View style={styles.line}></View>
    }

    onRefresh(){
        this.state.dataArray=[];
        pn=1;
        let url=URL+"?pn="+pn+PageSize;
        this.getPromise(url).then(result=> {
                this.setState({
                    dataSource: this.state.dataSource.cloneWithRows(result.data.results),
                    refreshing:false,
                    dataArray:result.data.results,
                })
            }
        ).catch(error=>{
            console.log(error)
        });
    }

    onEndReached(){
        //无论onEndReachedThreshold为多少,首次进来页面,都会调用onEndReached。第一次请求数据时,不加载数据
        // this.refs.toast.show("onEndReached0",DURATION.LENGTH_SHORT);
        if(this.state.isFirstIn){
            this.setState({
                isFirstIn:false,
            });
            return;
        }
        this.refs.toast.show("正在加载更多",DURATION.LENGTH_SHORT);
        pn++;
        let url=URL+"?pn="+pn+PageSize;
        this.getPromise(url).then(result=> {
                this.setState({
                    dataSource: this.state.dataSource.cloneWithRows(this.state.dataArray.concat(result.data.results)),
                    refreshing:false,
                    isFirstIn:false,
                    dataArray:this.state.dataArray.concat(result.data.results),
                })
            }
        ).catch(error=>{
            console.log(error)
        });
    }

    render(){
        return(
            <View style={styles.containers}>
                <ListView
                    dataSource={this.state.dataSource}
                    renderRow={(item)=>this.renderRow(item)}
                    renderSeparator={()=>this.renderLine()}

                    //RefreshControl:给ListView添加下拉刷新
                    //refreshing,在刷新时是否显示显示器,
                    //onRefresh刷新时执行
                    refreshControl={
                        <RefreshControl
                            refreshing={this.state.refreshing}
                            onRefresh={()=>this.onRefresh()}
                        />
                    }

                    onEndReachedThreshold={100}

                    onEndReached={
                        ()=>this.onEndReached()
                    }
                />
                {/*Toast在根视图的底部去使用,在视图被渲染时,把toast声明*/}
                <Toast
                    ref="toast"/>
            </View>
        )
    }
}

const styles=StyleSheet.create({
    containers: {
        flex:1,
    },
    line:{
        backgroundColor:'red',
        height:0.5,
    }
});

基本的过程就是,进入页面,显示下拉刷新控件,加载第一页的数据。
并且把第一页的数据添加到一个临时数组。

onEndReached,文档中这样说的,当所有的数据都已经渲染过,并且列表被滚动到距离最底部不足onEndReachedThreshold个像素的距离时调用。
可是无论设置onEndReachedThreshold为多少值,onEndReached总会先调用。
而我也发现了一个规律,onEndReachedThreshold可以理解为一个item的高度,如果你设置的onEndReachedThreshold值大于item高度,当拉到底部时,会触发该方法。如果过小,则不会触发。
对于有的item高度不方便计算的,onEndReachedThreshold写一个较大值即可。
在onEndReached中,则是把请求数据concat到临时数组,再添加给数据源。
而onRefresh下拉刷新时,清除临时数组。请求第一页数据显示。
自此,一个简单的React-native ListView下拉刷新加载更多的例子完成了。
为了方便调试,还使用Toast组件。

ListView的item的代码如下:

const ImageHost='http://101.201.78.24';

export default class ListViewItemDemo extends Component {

    constructor(props){
        super(props);
    }

    getActType(){
        var temp="";
        switch (this.props.item.type){
            case 0:
                temp="全部";
                break;
            case 1:
                temp="课程";
                break;
            case 2:
                temp="峰会";
                break;
            case 3:
                temp="路演";
                break;
            case 4:
                temp="沙龙";
                break;
            case 5:
                temp="其他";
                break;
        }
        return temp;
    }

    render(){
        return(
            <View style={styles.item}>
                    <View style={styles.leftSection}>
                    //默认的图片(图片加载不出来显示)
                        <Image
                            resizeMode='cover'
                            style={{width:120,height:80,position:'absolute'}}
                            source={require('../img/default_activity_list.jpg')}/>
                        <Image
                            resizeMode='cover'
                            style={{width:120,height:80,position:'absolute'}}
                            source={{uri:ImageHost+this.props.item.thumbnail}}/>
                    </View>

                    <View style={styles.rightSection}>
                        <Text style={{fontSize:18}}>{this.props.item.title}</Text>
                        <View style={{
                            marginVertical:10,
                            flexDirection:'row',
                        }}>
                            <Text>{this.props.item.startTime}</Text>
                            <Text style={{marginLeft:10}}>{this.props.item.city}</Text>
                        </View>

                        <View style={{
                            marginVertical:10,
                            flexDirection:'row',
                        }}>
                            <Text>{this.getActType()}</Text>
                        </View>
                    </View>
            </View>)
    }
}

const styles=StyleSheet.create({
    item: {
        flex:1,
        padding:15,
        flexDirection:'row',
    },
    leftSection:{
        position:'relative'
    },
    rightSection:{
        marginLeft:145,
        flexDirection:'column',
    },
});
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值