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

来源:互联网 发布:c语言中char 使用 编辑:程序博客网 时间:2024/05/24 03:24

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',    },});
阅读全文
0 0