React-Native 之 GD (七)下拉刷新 及 上拉加载更多

1.下拉刷新  使用第三方插件

下载插件:

$ npm install react-native-pull@latest --save

引入:

import {PullList} from 'react-native-pull';

将 ListView 改为 PullList 即可

GDHalfHourHot.js

/**
 * 近半小时热门
 */
import React, { Component } from 'react';
import {
    StyleSheet,
    Text,
    View,
    TouchableOpacity,
    Image,
    ListView,
    Dimensions,
    DeviceEventEmitter,
} from 'react-native';

// 获取屏幕宽高
const {width, height} = Dimensions.get('window');

// 引入自定义导航栏组件
import CommunalNavBar from '../main/GDCommunalNavBar';
// 引入 cell
import CommunalHotCell from '../main/GDCommunalHotCell';
// 引入 空白页组件
import NoDataView from '../main/GDNoDataView';
// 引入 下拉刷新组件
import {PullList} from 'react-native-pull';

export default class GDHalfHourHot extends Component {

    // 构造
    constructor(props) {
        super(props);
        // 初始状态
        this.state = {
            dataSource: new ListView.DataSource({rowHasChanged:(r1, r2) => r1 !== r2}), // 数据源 优化
            loaded: false, // 用于判断是否显示空白页
        };
        // 绑定
        this.fetchData = this.fetchData.bind(this);
    }

    // 网络请求
    fetchData(resolve) {
        // 测试没用数据的情况
        setTimeout(() => {
            fetch('http://guangdiu.com/api/gethots.php')  // 请求地址
            .then((response) => response.json())  // 定义名称 将数据转为json格式
            .then((responseData) => { // 处理数据
                // 修改dataSource的值
                this.setState({
                    dataSource: this.state.dataSource.cloneWithRows(responseData.data),
                    loaded:true,
                });
                // 关闭下来刷新动画
                if (resolve !== undefined) {
                    // 使用定时器 延时关闭动画
                    setTimeout(() => {
                        resolve();
                    },1000);
                }
            })
            .done(); // 结束
        },3000)
    }

    // 跳回首页
    popToHome() {
        this.props.navigator.pop();
    }

    // 返回中间按钮
    renderTitleItem() {
        return(
            <Text style={styles.navbarTitleItemStyle}>近半小时热门</Text>
        );
    }

    // 返回右边按钮
    renderRightItem() {
        return(
            <TouchableOpacity
                onPress={() => {this.popToHome()}}
            >
                <Text style={styles.navbarRightItemStyle}>关闭</Text>
            </TouchableOpacity>
        );
    }

    // 判断显示列表 还是 显示空白页
    renderListView() {
        if(this.state.loaded === false) {
            // 显示空白页
            return(
                <NoDataView />
            );
        }else{
            return(
                <PullList   // 将ListView 改为 PullList
                    // 下拉刷新
                    onPullRelease={(resolve) => this.fetchData(resolve)}
                    // 数据源 通过判断dataSource是否有变化,来判断是否要重新渲染
                    dataSource={this.state.dataSource} 
                    renderRow={this.renderRow}
                    // 隐藏水平线
                    showsHorizontalScrollIndicator={false}
                    style={styles.listViewStyle}
                    initialListSize={5}
                    // 返回 listView 头部
                    renderHeader={this.renderHeader}
                />
            );
        }
    }

    // 返回 listView 头部
    renderHeader() {
        return(
            <View style={styles.headerPromptStyle}>
                <Text>根据每条折扣的点击进行统计,每5分钟更新一次</Text>
            </View>
        );
    }

    // 返回每一行cell的样式
    renderRow(rowData) {
        // 使用cell组件
        return(
            <CommunalHotCell
                image={rowData.image}
                title={rowData.title}
            />
        );
    }

    componentWillMount() {
        // 向GDMain.js 发送通知 隐藏tabBar
        DeviceEventEmitter.emit('isHiddenTabBar', true);
    }

    componentWillUnmount() {
        // 向GDMain.js 发送通知 显示tabBar
        DeviceEventEmitter.emit('isHiddenTabBar', false);
    }

    // 生命周期 组件渲染完成 已经出现在dom文档里
    componentDidMount() {
        // 请求数据
        this.fetchData();
    }

    render() {
        return (
            <View style={styles.container}>
                {/* 导航栏样式 */}
                <CommunalNavBar
                    titleItem = {() => this.renderTitleItem()}
                    rightItem = {() => this.renderRightItem()}
                />

                {/* 根据网络状态决定是否渲染 listView */}
                {this.renderListView()}
            </View>
        );
    }
}

const styles = StyleSheet.create({
    container: {
        flex:1,
        alignItems: 'center',
    },

    navbarTitleItemStyle: {
        fontSize:17,
        color:'black',
        marginLeft:50
    },
    navbarRightItemStyle: {
        fontSize:17,
        color:'rgba(123,178,114,1.0)',
        marginRight:15
    },

    headerPromptStyle: {
        height:44,
        width,
        backgroundColor:'rgba(239,239,239,0.5)',
        justifyContent:'center',
        alignItems:'center'
    },

    listViewStyle: {
        width,
    }
});

效果图:

2.POST 带参数请求

// 网络请求
    fetchData(resolve) {
        // 初始化 formData
        let formData = new FormData();
        // 添加参数
        formData.append("count","5");
        formData.append("mall","京东商城");

        // 测试没用数据的情况
        setTimeout(() => {
            fetch('http://guangdiu.com/api/getlist.php', { // url 请求网址
                method: 'POST', // 请求方式
                headers:{}, // 设置请求头(默认为空对象)
                body:formData, // 将formData传给body
            })
            .then((response) => response.json())  // 定义名称 将数据转为json格式
            .then((responseData) => { // 处理数据
                // 修改dataSource的值
                this.setState({
                    dataSource: this.state.dataSource.cloneWithRows(responseData.data),
                    loaded:true,
                });
                // 关闭下来刷新动画
                if (resolve !== undefined) {
                    // 使用定时器 延时关闭动画
                    setTimeout(() => {
                        resolve();
                    },1000);
                }
            })
            .done(); // 结束
        });
    } 

3.navigator 跳转动画   关闭 Navigator 返回手势

有时候我们需要在跳转的时候使用不同的跳转动画,比如我们 半小时热门 的跳转方式在 iOS 内叫 模态跳转,特性就是当页面退出后会直接销毁,多用于注册、登录等不需要常驻内存的界面。

react-native 中为了方便实现这样的功能,我们可以在初始化 Navigator 的时候,在 ‘configsSence’ 中进行操作;具体操作如下:

// 设置Navigator跳转动画
    setNavAnimationType(route) {
        if(route.animationType) { // 外部有值传入
            // 关闭返回手势
            let conf = route.animationType;
            conf.gestures = null;
            return conf;
        }else{
            // 默认动画
            return Navigator.SceneConfigs.PushFromRight;
        }
    }
<Navigator
                // 设置路由
                initialRoute = {
                    {
                        name: selectedTab,
                        component: component
                    }
                }

                // 设置导航动画
                configureScene={(route) => this.setNavAnimationType(route)}

                renderScene = {
                    (route, navigator) => {
                        let Component = route.component;
                        return <Component {...route.params} navigator={navigator} />
                    }
                } /> 

这样我们在需要跳转的地方只需要传入相应的参数即可。

 // 跳转到近半小时热门
    pushToHalfHourHot() {
        // this.props 可以获取所有组件属性
        this.props.navigator.push({
            component: HalfHourHot,
            // 设置调整动画
            animationType: Navigator.SceneConfigs.FloatFromBottom,
        })
    } 

4.上拉加载更多

react-native-pull 框架的上拉加载使用也很简单,配合 onEndReached、onEndReachedThreshold、renderFooter使用

GDHome.js

/**
 * 首页
 */
import React, { Component } from 'react';
import {
    StyleSheet,
    Text,
    View,
    TouchableOpacity,
    Image,
    ListView,
    Dimensions,
    ActivityIndicator,
} from 'react-native';

// 引入 下拉刷新组件
import {PullList} from 'react-native-pull';
// 导航器
import CustomerComponents, {
    Navigator
} from 'react-native-deprecated-custom-components';

// 获取屏幕宽高
const {width, height} = Dimensions.get('window');

// 引入自定义导航栏组件
import CommunalNavBar from '../main/GDCommunalNavBar';
// 引入 近半小时热门组件
import HalfHourHot from './GDHalfHourHot';
// 引入 搜索页面组件
import Search from './GDSearch';
// 引入 cell
import CommunalHotCell from '../main/GDCommunalHotCell';
// 引入 空白页组件
import NoDataView from '../main/GDNoDataView';

export default class GDHome extends Component {

    // 构造
    constructor(props) {
        super(props);
        // 初始状态
        this.state = {
            dataSource: new ListView.DataSource({rowHasChanged:(r1, r2) => r1 !== r2}), // 数据源 优化
            loaded: false, // 用于判断是否显示空白页
        };
        // 绑定
        this.fetchData = this.fetchData.bind(this);
        this.loadMore = this.loadMore.bind(this);
    }

    // 网络请求
    fetchData(resolve) {
        // 初始化 formData
        let formData = new FormData();
        // 添加参数
        formData.append("count","5");
        formData.append("mall","京东商城");

        // 测试没用数据的情况
        setTimeout(() => {
            fetch('http://guangdiu.com/api/getlist.php', { // url 请求网址
                method: 'POST', // 请求方式
                headers:{}, // 设置请求头(默认为空对象)
                body:formData, // 将formData传给body
            })
            .then((response) => response.json())  // 定义名称 将数据转为json格式
            .then((responseData) => { // 处理数据
                // 修改dataSource的值
                this.setState({
                    dataSource: this.state.dataSource.cloneWithRows(responseData.data),
                    loaded:true,
                });
                // 关闭下来刷新动画
                if (resolve !== undefined) {
                    // 使用定时器 延时关闭动画
                    setTimeout(() => {
                        resolve();
                    },1000);
                }
            })
            .done(); // 结束
        });
    }

    // 跳转到近半小时热门
    pushToHalfHourHot() {
        // this.props 可以获取所有组件属性
        this.props.navigator.push({
            component: HalfHourHot,
            // 设置调整动画
            animationType: Navigator.SceneConfigs.FloatFromBottom,
        })
    }

    // 跳转到搜索页面
    pushToSearch() {
        this.props.navigator.push({
            component: Search,
        })
    }

    // 返回左边按钮
    renderLeftItem() {
        // 将组件返回出去
        return(
            <TouchableOpacity
                onPress={() => {this.pushToHalfHourHot()}}
            >
                <Image source={{uri:'hot_icon_20x20'}} style={styles.navbarLeftItemStyle} />
            </TouchableOpacity>
        );
    }

    // 返回中间按钮
    renderTitleItem() {
        return(
            <TouchableOpacity>
                <Image source={{uri:'navtitle_home_down_66x20'}} style={styles.navbarTitleItemStyle} />
            </TouchableOpacity>
        );
    }

    // 返回右边按钮
    renderRightItem() {
        return(
            <TouchableOpacity
                // 跳转搜索页面 
                onPress={() => {this.pushToSearch()}}
            >
                <Image source={{uri:'search_icon_20x20'}} style={styles.navbarRightItemStyle} />
            </TouchableOpacity>
        );
    }

    // 加载更多
    loadMore() {
        fetch('http://guangdiu.com/api/gethots.php')  // 请求地址
        .then((response) => response.json())  // 定义名称 将数据转为json格式
        .then((responseData) => { // 处理数据
            // 修改dataSource的值
            this.setState({
                dataSource: this.state.dataSource.cloneWithRows(responseData.data),
                loaded:true,
            });
        })
        .done(); // 结束
    }

    renderFooter() {
        return (
            <View style={{height: 100}}>
                <ActivityIndicator />
            </View>
        );
    }

    // 根据网络状态决定是否渲染 listView
    renderListView() {
        if(this.state.loaded === false) {
            // 显示空白页
            return(
                <NoDataView />
            );
        }else{
            return(
                <PullList   // 将ListView 改为 PullList
                    // 下拉刷新
                    onPullRelease={(resolve) => this.fetchData(resolve)}
                    // 数据源 通过判断dataSource是否有变化,来判断是否要重新渲染
                    dataSource={this.state.dataSource} 
                    renderRow={this.renderRow}
                    // 隐藏水平线
                    showsHorizontalScrollIndicator={false}
                    style={styles.listViewStyle}
                    initialListSize={5}
                    // 返回 listView 头部
                    renderHeader={this.renderHeader}
                    // 上拉加载更多
                    onEndReached={this.loadMore}
                    onEndReachedThreshold={60}
                    renderFooter={this.renderFooter}
                />
            );
        }
    }

    // 返回每一行cell的样式
    renderRow(rowData) {
        // 使用cell组件
        return(
            <CommunalHotCell
                image={rowData.image}
                title={rowData.title}
            />
        );
    }

    // 生命周期 组件渲染完成 已经出现在dom文档里
    componentDidMount() {
        // 请求数据
        this.fetchData();
    }

    render() {
        return (
            <View style={styles.container}>
                {/* 导航栏样式 */}
                <CommunalNavBar
                    leftItem = {() => this.renderLeftItem()}
                    titleItem = {() => this.renderTitleItem()}
                    rightItem = {() => this.renderRightItem()}
                />

                {/* 根据网络状态决定是否渲染 listView */}
                {this.renderListView()}
            </View>
        );
    }
}

const styles = StyleSheet.create({
    container: {
        flex: 1,
        alignItems: 'center',
    },
    navbarLeftItemStyle: {
        20,
        height:20,
        marginLeft:15,
    },
    navbarTitleItemStyle: {
        66,
        height:20,
    },
    navbarRightItemStyle: {
        20,
        height:20,
        marginRight:15,
    },

    listViewStyle: {
        width,
    },
});

效果图:

原文地址:https://www.cnblogs.com/crazycode2/p/7439807.html