自定义上下拉刷新----FlatList

效果图:

首次加载.png
下拉刷新.png
上拉刷新.png

FlatListPage文件

头文件包含

import {
    ActivityIndicator,
    Alert,
    Dimensions,
    FlatList,
    Image,
    RefreshControl,
    StyleSheet,
    Text,
    TouchableOpacity,
    View
} from 'react-native';
import {XLImageButton} from "../common/XLButton";
import {NavigationBarTitle} from "../common/NavigationBarTitle";
import {appStyle} from "../style/BaseStyles";

列表json数据

const list = [{
    title: '美仁枣300g',
    imageUrl: 'https://a.vpimg4.com/upload/merchandise/pdcvis/602520/2018/0611/93/7f380e8c-627e-4162-b68c-a16ad98f9609_5t.jpg',
    price: 38,
}, {
    title: '2件起售】香蕉干90g',
    imageUrl: 'https://a.vpimg2.com/upload/merchandise/pdcvis/610789/2018/0420/114/54c7ae6a-1b94-44d9-bd38-0d46326aa683_t.jpg',
    price: 19,
}, {
    title: '【2件起售】七彩葡萄干420g',
    imageUrl: 'https://a.vpimg3.com/upload/merchandise/pdcvis/602520/2018/0611/81/faf4abe6-e212-4347-9369-118028bec2fe_5t.jpg',
    price: 27,
}, {
    title: '优你康罐装牛奶双味棒棒糖720g',
    imageUrl: 'https://a.vpimg3.com/upload/merchandise/pdcvis/605346/2018/0509/184/5a1c29d8-b127-40c5-b239-4b0c5b5b1e1b.jpg',
    price: 128,
}, {
    title: '滇园南枣核桃糕148g*2福建特产小吃休闲糖果零食软糖喜糖',
    imageUrl: 'https://a.vpimg4.com/upload/merchandise/pdcvis/606282/2018/0424/132/5bf877ba-9a13-4f85-a67c-2ea2fbbe13f9_t.jpg',
    price: 59,
}, {
    title: '【2件起售】自然派榴莲糖200g',
    imageUrl: 'https://a.vpimg2.com/upload/merchandise/pdcvis/605222/2018/0320/1/9edf6130-35f1-4af8-9034-bf37a617c82a.jpg',
    price: 22,
}, {
    title: '【乐奈】8口味速融巧克力408g',
    imageUrl: 'https://a.vpimg3.com/upload/merchandise/pdcvis/131932/2018/0530/137/083642ef-5fef-446c-b279-7a3047ba058e_5t.jpg',
    price: 39,
}, {
    title: '【BK】魔彩巧克力礼盒250g',
    imageUrl: 'https://a.vpimg3.com/upload/merchandise/pdcvis/600876/2018/0324/158/b3fed03e-3cd8-40c7-b53d-19630adb2d31_t.jpg',
    price: 86,
}, {
    title: '【2件起售】乐奈烤巧克力72g',
    imageUrl: 'https://a.vpimg3.com/upload/merchandise/pdcvis/131932/2017/1223/15/060b8ff9-674e-4869-9845-a8aee1f435a9_t.jpg',
    price: 22,
}, {
    title: '每日坚果A款混合果仁果干孕妇零食坚果小礼盒175克',
    imageUrl: 'https://a.vpimg4.com/upload/merchandise/pdcvis/602656/2018/0313/108/924c4a5b-7315-40bd-9d5f-84fb2fd489a2.jpg',
    price: 39,
}, {
    title: '每日坚果A款混合果仁果干孕妇零食坚果礼盒750克',
    imageUrl: 'https://a.vpimg2.com/upload/merchandise/pdcvis/2018/04/25/144/2a6462ca-bc0a-4ffb-9f43-d1e6fae63baf_235x297_90.jpg',
    price: 199,
}, {
    title: '鹰嘴豆250g',
    imageUrl: 'https://a.vpimg3.com/upload/merchandise/pdcvis/602520/2018/0611/195/11f3c35b-12dc-4263-ad80-f2fa9a5b5c37_5t.jpg',
    price: 16,
}, {
    title: '【2件起售】蔓越莓干核桃仁118g',
    imageUrl: 'https://a.vpimg3.com/upload/merchandise/pdcvis/602520/2018/0611/74/5b521a8e-2b51-41a4-b120-3e06e799be1b_5t.jpg',
    price: 28,
},
];

FlatListPage类实现

export default class FlatListPage extends Component {

    static navigationOptions = ({navigation, screenProps}) => ({
        headerStyle: {
            backgroundColor: '#fff'
        },
        headerLeft: ( // 设置左边的标签
            <XLImageButton
                imageStyle={appStyle.backIcon}
                clickAction={() => {
                    const {goBack} = navigation;
                    goBack();
                }}
            />
        ),
        headerTitle: (
            <NavigationBarTitle title={'FlatList'}/>
        ),
    });
    constructor(props) {
        super(props);
        this.state = {
            data: [],
            isRefreshing: false,
            isShowLoadMore: false,
        }
    }
    render() {
        return (
            <View style={styles.container}>
                <FlatList
                    style={{flex: 1}}
                    data={this.state.data}
                    numColumns={column}
                    horizontal={false}
                    //注意参数名:item  是固定的
                    renderItem={({item, index}) => {
                        return <TouchableOpacity
                            style={styles.cellStyle}
                            onPress={() => {
                                Alert.alert(item.title);
                            }}
                            opacity={0.5}
                        >
                            <View style={{flex: 1, alignItems: 'center'}}>
                                <Image style={{width: window.width / (column + 1), height: window.width / (column + 1)}}
                                       source={{uri: item.imageUrl}}/>
                                <Text numberOfLines={1}
                                      style={[styles.titleStyle, {textAlign: 'left'}]}>{item.title}</Text>
                                <Text style={styles.priceStyle}>{'¥' + item.price}</Text>
                            </View>

                        </TouchableOpacity>
                    }}
                    refreshControl={
                        <RefreshControl
                            tintColor="#ff0000"
                            title="Loading..."
                            titleColor="#00ff00"
                            colors={['#ff0000', '#00ff00', '#0000ff']}
                            progressBackgroundColor="#ffff00"
                            refreshing={this.state.isRefreshing}
                            onRefresh={() => {
                                this.setState({isRefreshing: true});
                                setTimeout(() => {
                                    this.setState({
                                        isRefreshing: false,
                                        data: list,
                                    });
                                }, 2000);
                            }}/>
                    }
                    ListEmptyComponent={() => {
                        return <View style={[styles.container, {alignItems: 'center'}]}>
                            <Text style={styles.noDataText}>暂无数据...</Text>
                        </View>
                    }}
                    onEndReachedThreshold={0.1}//当前可视列表高度的十分之一
                    onEndReached={(info: { distanceFromEnd: number }) => {
                        if (this.state.data.length > 30 || this.state.isShowLoadMore) {//控制是否还有更多可加载
                            return null;
                        }
                        this.setState({
                            isShowLoadMore: true,//显示加载更多指示器
                        }, function (finish) {
                            //拼接数据
                            const data = this.state.data.concat(list);
                            setTimeout(() => {
                                this.setState({
                                    data: data,
                                }, function (finish) {
                                    this.setState({
                                        isShowLoadMore: false,
                                    })
                                });
                            }, 2000);
                        })
                    }}
                    ListFooterComponent={() => {
                        return this.state.isShowLoadMore ? <View style={styles.indicator}>
                            <ActivityIndicator
                                color={'#f00'}
                                size={'small'}
                            />
                        </View> : null
                    }}
                />
            </View>
        )
    }
}

本文件样式

const styles = StyleSheet.create({
    container: {
        flex: 1,
        backgroundColor: '#fff',
    },
    lineStyle: {
        flex: 1,
        height: 0.5,
        backgroundColor: '#999',
    },
    cellText: {
        lineHeight: 44,
        marginHorizontal: 15,
        color: '#666',
    },
    headerStyle: {
        height: 40,
        justifyContent: 'center',
        paddingHorizontal: 10,
        backgroundColor: "#ffead1"
    },
    cellStyle: {
        marginVertical: 10,
        width: window.width / column,
    },
    titleStyle: {
        padding: 5,
        color: '#666',
    },
    priceStyle: {
        color: '#f00',
        paddingHorizontal: 5,
        // textDecorationLine: 'line-through',//删除线
    },
    indicator: {
        height: 30,
        alignItems: 'center',
        justifyContent: 'center',
    },
    noDataText: {
        color: '#666',
        lineHeight: 50
    }
});

XLButton 文件实现

/*
* 自定义组件:按钮
*
* */
import React, {Component} from 'react';
import PropTypes from 'prop-types';
import {Image, StyleSheet, Text, TouchableOpacity,} from 'react-native';
//文字按钮
export class XLButton extends Component {

    static defaultProp = {
        title: 'button',//标题
        color: '#333',//字体颜色
        titleStyle: null,//标题风格text
        textAlign: 'center',//文字居中
        fontSize: 15,//字体大小
        backgroundColor: 'rgba(0,0,0,0)',//背景颜色
        borderRadius: 0,//背景圆角
        borderColor: '#fff',//边框颜色
        borderWidth: 0,//边框宽度
        backgroundStyle: null,//背景风格
        clickAction: null,//事件点击
        tag: 0,//索引标记
        data: null,//数据项
    };
    static propTypes = {
        title: PropTypes.string,//标题
        color: PropTypes.string,//字体颜色
        fontSize: PropTypes.number,//字体大小
        textAlign: PropTypes.string,//文字居中
        borderRadius: PropTypes.number,//背景圆角
        borderColor: PropTypes.string,//边框颜色
        borderWidth: PropTypes.number,//边框宽度
        clickAction: PropTypes.func,//事件点击
        tag: PropTypes.number,//索引标记
        data: PropTypes.any,//数据项
    };
    render() {
        return (
            <TouchableOpacity
                style={[{
                    backgroundColor: this.props.backgroundColor,
                    borderWidth: this.props.borderWidth,
                    borderColor: this.props.borderColor,
                    borderRadius: this.props.borderRadius
                }, this.props.backgroundStyle ? this.props.backgroundStyle : null]}
                onPress={() => {
                    if (this.props.clickAction) {
                        this.props.clickAction(this.props.tag, this.props.data);
                    }
                }}
            >
                <Text style={[{
                    color: this.props.color,
                    fontSize: this.props.fontSize,
                    textAlign: this.props.textAlign
                },
                    this.props.titleStyle ? this.props.titleStyle : null]}
                >{this.props.title}</Text>

            </TouchableOpacity>
        );
    }
}
//图片按钮
export class XLImageButton extends XLButton {
    static defaultProp = {
        image: null,
        imageUrl: null,
        imageStyle: null,
    };
    static propTypes = {
        image: PropTypes.object,
        imageUrl: PropTypes.number,
    };
    constructor(props) {
        super(props);
    }
    render() {
        return (
            <TouchableOpacity
                style={[{
                    backgroundColor: this.props.backgroundColor,
                    borderWidth: this.props.borderWidth,
                    borderColor: this.props.borderColor,
                    borderRadius: this.props.borderRadius
                }, this.props.backgroundStyle ? this.props.backgroundStyle : null]}
                onPress={() => {
                    if (this.props.clickAction) {
                        this.props.clickAction(this.props.tag, this.props.data);
                    }
                }}
            >
                <Image style={[this.props.imageStyle ? this.props.imageStyle : styles.imageIcon]}
                       source={this.props.imageUrl ? {uri: this.props.imageUrl} :
                           this.props.image ? this.props.image : require('../../res/nav/navBack.png')}
                />
            </TouchableOpacity>
        );
    }
}
const styles = StyleSheet.create({
    imageIcon: {
        width: 10,
        height: 18,
        marginHorizontal: 10,
        marginVertical: 5,
    }
});

公用导航栏适配:NavigationBarTitle

import React, {Component} from 'react';
import PropTypes from 'prop-types';
import {Text, View,} from 'react-native';
import {appStyle} from "../style/BaseStyles";

export class NavigationBarTitle extends Component {
    static defaultProp = {
        title: 'title',//标题
    };
    static propTypes = {
        title: PropTypes.string,//标题
    };
    render() {
        return (
            <View style={appStyle.headerTitleStyle}>
                <Text style={appStyle.navTitleStyle}>{this.props.title}</Text>
            </View>
        );
    }
}

通用样式文件:BaseStyles

import {StyleSheet,Dimensions} from 'react-native';
const window = Dimensions.get('window');

export const appStyle = StyleSheet.create({
    backIcon: {
        width: 10,
        height: 18,
        marginHorizontal: 15,
    },
    baseTextColor: {
        color: '#FE6634',
    },
    navTitleStyle:{
       fontSize:17,
        fontWeight:'bold',
       color:'#333',
       textAlign:'center',
    },
    viewBGColor:{
        backgroundColor:'#f5f5f5',
    },
    headerTitleStyle:{
        width:window.width-120,
        justifyContent:'center',
    },
});

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 162,547评论 4 374
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,787评论 2 308
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 112,175评论 0 254
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,752评论 0 223
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 53,169评论 3 297
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 41,056评论 1 226
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,195评论 2 321
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,980评论 0 214
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,724评论 1 250
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,872评论 2 254
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,344评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,667评论 3 264
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,379评论 3 245
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,202评论 0 9
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,992评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,189评论 2 286
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,987评论 2 279

推荐阅读更多精彩内容