React Native_手把手教你做项目(五.下拉刷新RefreshControl&封装自定义Cell)

接下来我们继续下拉刷新的功能,主要是缓存数据的拼接与后台服务器的配合。把数据最后的id传给后台,后台根据id返回给你新的id之后的数据,因为没有服务器,所以这里的代码仅仅做演示使用。

下拉刷新RefreshControl

list.js

import React, {Component} from 'react';
import {
    Platform,
    StyleSheet,
    Text,
    View,
    ListView,
    TouchableOpacity,
    Image,
    ActivityIndicator,
    RefreshControl
} from 'react-native';

import Icon from 'react-native-vector-icons/Ionicons';
import Dimensions from 'Dimensions';

const {width, height} = Dimensions.get('window');

import config from '../common/config';
import request from '../common/request';

// Mockjs 解析随机的文字
import  Mock from 'mockjs';

let cachedResult = {
    nexPage: 1,
    item: [],
    total: 0,
}

export default class list extends Component {
    constructor(props) {
        super(props);
        this.state = {
            dataSource: new ListView.DataSource({
                rowHasChanged: (r1, r2)=>r1 !== r2,
            }),
            isLoadingTail: false,  //没有加载数据
            isRefreshing: false
        }
    }

    //即将显示
    componentWillMount() {
        //加载本地数据
        // this.dsfetchData();
    }

    componentDidMount() {
        //加载网络数据
        this._fetchData(1);
    }

    _fetchData(page) {

        if (page !== 0) {
            this.setState({
                isLoadingTail: true
            });
        } else {
            this.setState({
                isRefreshing: true
            });
        }

        this.setState({
            isLoadingTail: true
        });

        //发送网络请求
        request.get(config.api.base + config.api.list, {
            accessToken: '001',
            a: 'list',
            c: 'data',
            type: 29,
            page: page
        }).then(
            (data) => {
                //将服务器得到的数据缓存进来
                let items = cachedResult.item.slice();
                // let items = cachedResult.item.concat(data.list);//把缓存的数据进行拼接
                if (page !== 0) {//加载更多
                    items = items.concat(data.list);
                    cachedResult.nexPage += 1;
                } else {//刷新数据
                    items = data.list.concat(items);
                }
                //最后保存数据
                cachedResult.item = items;
                cachedResult.total = items.total;
                // console.log(items);
                // console.log('总数据是:' + cachedResult.total);
                // console.log('当前到了第:' + cachedResult.item.length + '个!');

                if (page !== 0) {//加载更多
                    this.setState({
                        dataSource: this.state.dataSource.cloneWithRows(
                            cachedResult.item
                        ),
                        isLoadingTail: false
                    });
                }else {
                    this.setState({
                        dataSource: this.state.dataSource.cloneWithRows(
                            cachedResult.item
                        ),
                        isRefreshing: false
                    });
                }

            }
        ).catch(//如果有错
            (error) => {
                if(page !=0){
                    this.setState({
                        isLoadingTail:false
                    })
                }else {
                    this.setState({
                        isRefreshing:false
                    })
                }
                console.log('err' + error);
            }
        )
    }

    // dsfetchData() {
    //     let result = Mock.mock({
    //         "data|20": [
    //             {
    //                 "_id": "@ID",
    //                 "thumb": "@IMG(1024x700,@COLOR(),\'\u56fe\u7247\u4e0a\u7684\u6587\u5b57\')",
    //                 "title": "@cparagraph(1, 3)",
    //                 "video": "\'http:\/\/v.youku.com\/v_show\/id_XMzY5ODY5MDI3Ng==.html?spm=a2h1n.8251846.0.0\'"
    //             }
    //         ],
    //         "success": true
    //     })
    //     this.setState({
    //         dataSource: this.state.dataSource.cloneWithRows(result.data)
    //     })
    // }

    render() {
        return (
            <View style={styles.container}>
                {/*导航条*/}
                <View style={styles.header}>
                    <Text style={styles.headerText}>
                        视频列表
                    </Text>
                </View>
                {/*列表页面*/}
                <ListView
                    dataSource={this.state.dataSource}
                    renderRow={this._renderRow}
                    style={styles.listView}
                    onEndReached={this._fetchMoreData}//滚到底部加载更多数据
                    onEndReachedThreshold={20} //距离底部还有多远触发
                    renderFooter={this._renderFooter}

                    refreshControl={
                        <RefreshControl
                            refreshing={this.state.isRefreshing}
                            onRefresh={this._onRefresh}
                        />
                    }
                />
            </View>
        );
    }

    _onRefresh = ()=> {
        if (!this._hasMore() || this.state.isRefreshing) {
            return
        }

        this._fetchData(0);
    }
    //自定义Footer视图
    _renderFooter = ()=> {
        if (!this._hasMore() && cachedResult.total !== 0) {
            return (
                <View style={styles.loadingMore}>
                    <Text style={styles.loadingText}>没有更多数据啦...</Text>
                </View>
            )
        }
        // if(!this.state.isLoadingTail){
        //     return(<View></View>)
        // }
        //显示一朵小菊花
        return (
            <ActivityIndicator style={styles.loadingMore}></ActivityIndicator>
        )
    }


    //思路:有多种解决方案

    //1.发送请求 2.保存请求参数 3.对比参数

    //刷新请求 2.保存request = refresh 3.对比 refresh==保存request 状态机中的page值
    //状态机 loading = refresh
    //上拉加载更多数据
    _fetchMoreData = ()=> {
        //判断是否有更多数据或者是否在请求中
        if (!this._hasMore || this.isLoadingTail) {
            return
        }

        let page = cachedResult.nexPage;
        //去服务器去加载更多数据
        this._fetchData(page);
    }

    //判断是否还有更多数据
    _hasMore() {
        return cachedResult.item.length !== cachedResult.total;
    }

    //下划线代表内部类自己用的函数,属于规范
    _renderRow = (rowData)=> {
        return (
            <TouchableOpacity>

                {/*整个Cell*/}
                <View style={styles.cellStyle}>
                    {/*标题文字*/}
                    <Text style={styles.title}>{rowData.text}</Text>


                    <Image style={styles.thumb} source={{uri: rowData.profile_image}}>

                    </Image>
                    <Icon name="ios-play"
                          size={30}
                          style={styles.play}
                    />
                    {/*点赞&评论*/}
                    <View style={styles.cellFooter}>
                        {/*点赞*/}
                        <View style={styles.footerBox}>
                            <Icon name="ios-heart-outline"
                                  size={30}
                                  style={styles.boxIcon}
                            />
                            {/*点赞文字*/}
                            <Text style={styles.boxText}>点赞</Text>
                        </View>

                        {/*评论*/}
                        <View style={styles.footerBox}>
                            <Icon name="ios-chatbubbles-outline"
                                  size={30}
                                  style={styles.boxIcon}
                            />
                            {/*点赞文字*/}
                            <Text style={styles.boxText}>评论</Text>
                        </View>
                    </View>
                </View>
            </TouchableOpacity>
        );
    }
}

const styles = StyleSheet.create({
    container: {
        flex: 1,
        backgroundColor: '#F5FCFF',
    },
    header: {
        // marginTop:Platform.OS == 'ios'?20:0,
        paddingTop: 25,
        paddingBottom: 15,
        backgroundColor: '#dddddd',
        borderBottomWidth: 0.5,
        borderBottomColor: 'black',
    },
    headerText: {
        fontWeight: '600',
        textAlign: 'center',
        fontSize: 16,
    },
    listView: {},
    cellStyle: {
        width: width,
        marginTop: 10,
        backgroundColor: 'white',

    },
    title: {
        padding: 10,
        color: 'black',
        fontSize: 18
    },
    thumb: {
        width: width,
        height: width * 0.56,
        resizeMode: 'cover'
    },
    play: {
        position: 'absolute',
        bottom: 100,
        right: 14,
        width: 46,
        height: 46,
        paddingTop: 8,
        paddingLeft: 18,
        backgroundColor: 'transparent',
        borderColor: 'black',
        borderWidth: 0.5,
        borderRadius: 23,
    },
    cellFooter: {
        flexDirection: 'row',
        justifyContent: 'space-between',
        backgroundColor: '#dddddd',
    },
    footerBox: {
        padding: 10,
        flexDirection: 'row',
        backgroundColor: 'white',
        flex: 1,
        marginLeft: 1,
        justifyContent: 'center',

    },
    boxIcon: {
        fontSize: 22,
        color: '#333',
    },
    boxText: {
        fontSize: 18,
        color: '#333',
        paddingLeft: 12,
        marginTop: 2
    },
    loadingMore: {
        marginVertical: 20
    },
    loadingText: {
        fontSize: 18,
        color: '#777',
        textAlign: 'center'
    }
});

演示示例:

这里写图片描述

封装自定义Cell

从上面的代码中,我们可以看出,仅仅这么low的一个页面,包括css样式,js逻辑代码和render html界面都在list.js文件中,代码300多行,显得十分混乱,那么我们能不能把cell进行抽取呢?

List文件下创建Item.js文件

Item.js

/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 * @flow
 */

import React, {Component} from 'react';
import {
    Platform,
    StyleSheet,
    Text,
    View,
    TouchableOpacity,
    Image
} from 'react-native';

import Dimensions from 'Dimensions';
const {width, height} = Dimensions.get('window');
import Icon from 'react-native-vector-icons/Ionicons';

export default class item extends Component {

    constructor(props) {
        super(props);
        this.state = {
            rowData: this.props.rowData,
        }
    }

    render() {
        let rowData = this.state.rowData;

        return (
            <TouchableOpacity>

                {/*整个Cell*/}
                <View style={styles.cellStyle}>
                    {/*标题文字*/}
                    <Text style={styles.title}>{rowData.text}</Text>


                    <Image style={styles.thumb} source={{uri: rowData.profile_image}}>

                    </Image>
                    <Icon name="ios-play"
                          size={30}
                          style={styles.play}
                    />
                    {/*点赞&评论*/}
                    <View style={styles.cellFooter}>
                        {/*点赞*/}
                        <View style={styles.footerBox}>
                            <Icon name="ios-heart-outline"
                                  size={30}
                                  style={styles.boxIcon}
                            />
                            {/*点赞文字*/}
                            <Text style={styles.boxText}>点赞</Text>
                        </View>

                        {/*评论*/}
                        <View style={styles.footerBox}>
                            <Icon name="ios-chatbubbles-outline"
                                  size={30}
                                  style={styles.boxIcon}
                            />
                            {/*点赞文字*/}
                            <Text style={styles.boxText}>评论</Text>
                        </View>
                    </View>
                </View>
            </TouchableOpacity>
        );
    }
}

const styles = StyleSheet.create({
    cellStyle: {
        width: width,
        marginTop: 10,
        backgroundColor: 'white',

    },
    title: {
        padding: 10,
        color: 'black',
        fontSize: 18
    },
    thumb: {
        width: width,
        height: width * 0.56,
        resizeMode: 'cover'
    },
    play: {
        position: 'absolute',
        bottom: 100,
        right: 14,
        width: 46,
        height: 46,
        paddingTop: 8,
        paddingLeft: 18,
        backgroundColor: 'transparent',
        borderColor: 'black',
        borderWidth: 0.5,
        borderRadius: 23,
    },
    cellFooter: {
        flexDirection: 'row',
        justifyContent: 'space-between',
        backgroundColor: '#dddddd',
    },
    footerBox: {
        padding: 10,
        flexDirection: 'row',
        backgroundColor: 'white',
        flex: 1,
        marginLeft: 1,
        justifyContent: 'center',
    },
    boxIcon: {
        fontSize: 22,
        color: '#333',
    },
    boxText: {
        fontSize: 18,
        color: '#333',
        paddingLeft: 12,
        marginTop: 2
    }
});

list.js

/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 * @flow
 */

import React, {Component} from 'react';
import {
    Platform,
    StyleSheet,
    Text,
    View,
    ListView,
    TouchableOpacity,
    Image,
    ActivityIndicator,
    RefreshControl
} from 'react-native';

import Icon from 'react-native-vector-icons/Ionicons';
import Dimensions from 'Dimensions';

const {width, height} = Dimensions.get('window');

import config from '../common/config';
import request from '../common/request';

import Item from './Item';

// Mockjs 解析随机的文字
import  Mock from 'mockjs';

let cachedResult = {
    nexPage: 1,
    item: [],
    total: 0,
}

export default class list extends Component {
    constructor(props) {
        super(props);
        this.state = {
            dataSource: new ListView.DataSource({
                rowHasChanged: (r1, r2)=>r1 !== r2,
            }),
            isLoadingTail: false,  //没有加载数据
            isRefreshing: false
        }
    }

    //即将显示
    componentWillMount() {
        //加载本地数据
        // this.dsfetchData();
    }

    componentDidMount() {
        //加载网络数据
        this._fetchData(1);
    }

    _fetchData(page) {

        if (page !== 0) {
            this.setState({
                isLoadingTail: true
            });
        } else {
            this.setState({
                isRefreshing: true
            });
        }

        this.setState({
            isLoadingTail: true
        });

        //发送网络请求
        request.get(config.api.base + config.api.list, {
            accessToken: '001',
            a: 'list',
            c: 'data',
            type: 29,
            page: page
        }).then(
            (data) => {
                //将服务器得到的数据缓存进来
                let items = cachedResult.item.slice();
                // let items = cachedResult.item.concat(data.list);//把缓存的数据进行拼接
                if (page !== 0) {//加载更多
                    items = items.concat(data.list);
                    cachedResult.nexPage += 1;
                } else {//刷新数据
                    items = data.list.concat(items);
                }
                //最后保存数据
                cachedResult.item = items;
                cachedResult.total = items.total;
                // console.log(items);
                // console.log('总数据是:' + cachedResult.total);
                // console.log('当前到了第:' + cachedResult.item.length + '个!');

                if (page !== 0) {//加载更多
                    this.setState({
                        dataSource: this.state.dataSource.cloneWithRows(
                            cachedResult.item
                        ),
                        isLoadingTail: false
                    });
                }else {
                    this.setState({
                        dataSource: this.state.dataSource.cloneWithRows(
                            cachedResult.item
                        ),
                        isRefreshing: false
                    });
                }

            }
        ).catch(//如果有错
            (error) => {
                if(page !=0){
                    this.setState({
                        isLoadingTail:false
                    })
                }else {
                    this.setState({
                        isRefreshing:false
                    })
                }
                console.log('err' + error);
            }
        )
    }

    render() {
        return (
            <View style={styles.container}>
                {/*导航条*/}
                <View style={styles.header}>
                    <Text style={styles.headerText}>
                        视频列表
                    </Text>
                </View>
                {/*列表页面*/}
                <ListView
                    dataSource={this.state.dataSource}
                    renderRow={this._renderRow}
                    style={styles.listView}
                    onEndReached={this._fetchMoreData}//滚到底部加载更多数据
                    onEndReachedThreshold={20} //距离底部还有多远触发
                    renderFooter={this._renderFooter}

                    refreshControl={
                        <RefreshControl
                            refreshing={this.state.isRefreshing}
                            onRefresh={this._onRefresh}
                        />
                    }
                />
            </View>
        );
    }

    //下拉刷新
    _onRefresh = ()=> {
        if (!this._hasMore() || this.state.isRefreshing) {
            return
        }

        this._fetchData(0);
    }
    //自定义Footer视图
    _renderFooter = ()=> {
        if (!this._hasMore() && cachedResult.total !== 0) {
            return (
                <View style={styles.loadingMore}>
                    <Text style={styles.loadingText}>没有更多数据啦...</Text>
                </View>
            )
        }
        // if(!this.state.isLoadingTail){
        //     return(<View></View>)
        // }
        //显示一朵小菊花
        return (
            <ActivityIndicator style={styles.loadingMore}></ActivityIndicator>
        )
    }


    //思路:有多种解决方案

    //1.发送请求 2.保存请求参数 3.对比参数

    //刷新请求 2.保存request = refresh 3.对比 refresh==保存request 状态机中的page值
    //状态机 loading = refresh
    //上拉加载更多数据
    _fetchMoreData = ()=> {
        //判断是否有更多数据或者是否在请求中
        if (!this._hasMore || this.isLoadingTail) {
            return
        }

        let page = cachedResult.nexPage;
        //去服务器去加载更多数据
        this._fetchData(page);
    }

    //判断是否还有更多数据
    _hasMore() {
        return cachedResult.item.length !== cachedResult.total;
    }

    //返回item
    //下划线代表内部类自己用的函数,属于规范
    _renderRow = (rowData)=> {
        return (
           <Item rowData={rowData} />
        );
    }
}

const styles = StyleSheet.create({
    container: {
        flex: 1,
        backgroundColor: '#F5FCFF',
    },
    header: {
        // marginTop:Platform.OS == 'ios'?20:0,
        paddingTop: 25,
        paddingBottom: 15,
        backgroundColor: '#dddddd',
        borderBottomWidth: 0.5,
        borderBottomColor: 'black',
    },
    headerText: {
        fontWeight: '600',
        textAlign: 'center',
        fontSize: 16,
    },
    listView: {

    },
    loadingMore: {
        marginVertical: 20
    },
    loadingText: {
        fontSize: 18,
        color: '#777',
        textAlign: 'center'
    }
});

代码抽取很简单,可以详细看看抽取了哪些代码。

猜你喜欢

转载自blog.csdn.net/wtdask/article/details/81116819