https://github.com/razor1895/react-native-refreshable-flatlist

这个库对flatlist进行了封装,使其在保留flatlist属性的前提下额外多了一些属性:

showTopIndicator: bool 是否显示顶部加载器

showBottomIndicator: bool 是否显示底部加载器

topIndicatorComponent: oneOfType([func, element]) 顶部加载器组件

bottomIndicatorComponent: oneOfType([func, element]) 底部加载器组件

minDisplayTime: number 最小显示时间

minPullDownDistance: number 最小下拉距离

minPullUpDistance: number 最小上拉距离

onRefreshing: func onLoadMore: func 不同于flatlist需要返回一个Promise对象

onRefreshing={() => new Promise((r) => {         //必须是promise否则没有加载动画
                        setTimeout(() => {
                            r();
                        }, 3000);
                    })}

对于网络请求,因为fetch Api本身就返回Promise对象,所以可以直接用

onRefreshing={() => fetch(url, options).then(res => {
  //...do sth with the response
})}

常用的自定义加载器代码,使用了一张“箭头”图片,然后根据不同状态旋转不同角度,加载中使用ActivityIndicator效果

import React, { Component } from 'react';
import {
    View,
    Text,
    StyleSheet,
    Animated,
    ActivityIndicator,
    Easing
} from 'react-native';
import PropTypes from 'prop-types';

export default class CustomIndicator extends Component {
    static propTypes = {
        refreshing: PropTypes.bool.isRequired,
        scrollStatus: PropTypes.oneOf([
            'NOT_EXCEEDED_MIN_PULL_DOWN_DISTANCE',
            'NOT_EXCEEDED_MIN_PULL_UP_DISTANCE',
            'EXCEEDED_MIN_PULL_DOWN_DISTANCE',
            'EXCEEDED_MIN_PULL_UP_DISTANCE'
        ]).isRequired,
        styles: PropTypes.object.isRequired,
        topPullingPrompt: PropTypes.oneOfType([PropTypes.string, PropTypes.element]).isRequired,
        topHoldingPrompt: PropTypes.oneOfType([PropTypes.string, PropTypes.element]).isRequired,
        topRefreshingPrompt: PropTypes.oneOfType([PropTypes.string, PropTypes.element]).isRequired,
        bottomPullingPrompt: PropTypes.oneOfType([PropTypes.string, PropTypes.element]).isRequired,
        bottomHoldingPrompt: PropTypes.oneOfType([PropTypes.string, PropTypes.element]).isRequired,
        bottomRefreshingPrompt: PropTypes.oneOfType([PropTypes.string, PropTypes.element]).isRequired,
    };

    constructor() {
        super();
        this.state = {
            topArrowDeg: new Animated.Value(0),
            bottomArrowDeg: new Animated.Value(0),
        };
        this.topArrowTransform = [{
            rotate: this.state.topArrowDeg.interpolate({
                inputRange: [0, 1],
                outputRange: ['0deg', '-180deg']
            })
        }];
        this.bottomArrowTransform = [{
            rotate: this.state.bottomArrowDeg.interpolate({
                inputRange: [0, 1],
                outputRange: ['-180deg', '0deg']
            })
        }];
    }

    renderIndicatorIcon() {
        let indicator;
        const { scrollStatus } = this.props;

        if (this.props.refreshing && (scrollStatus === 'EXCEEDED_MIN_PULL_DOWN_DISTANCE' || scrollStatus === 'EXCEEDED_MIN_PULL_UP_DISTANCE')) {
            indicator = <ActivityIndicator size="small" color="gray" style={styles.indicator} />;
        } else if (scrollStatus.indexOf('DOWN') > -1) {
            indicator = (
                <Animated.Image
                    style={[styles.indicator, { transform: this.topArrowTransform }]}
                    resizeMode={'cover'}
                    source={require('../images/arrow_down.png')}    //这里传入了一张“箭头”图片
                />
            );
        } else {
            indicator = (
                <Animated.Image
                    style={[styles.indicator, { transform: this.bottomArrowTransform }]}
                    resizeMode={'cover'}
                    source={require('../images/arrow_down.png')}
                />
            );
        }

        if (scrollStatus === 'EXCEEDED_MIN_PULL_DOWN_DISTANCE') {
            Animated.timing(this.state.topArrowDeg, {
                toValue: 1,
                duration: 100,
                easing: Easing.linear
            }).start();
        } else if (scrollStatus === 'NOT_EXCEEDED_MIN_PULL_DOWN_DISTANCE') {
            Animated.timing(this.state.topArrowDeg, {
                toValue: 0,
                duration: 100,
                easing: Easing.linear
            }).start();
        } else if (scrollStatus === 'EXCEEDED_MIN_PULL_UP_DISTANCE') {
            Animated.timing(this.state.bottomArrowDeg, {
                toValue: 1,
                duration: 100,
                easing: Easing.linear
            }).start();
        } else if (scrollStatus === 'NOT_EXCEEDED_MIN_PULL_UP_DISTANCE') {
            Animated.timing(this.state.bottomArrowDeg, {
                toValue: 0,
                duration: 100,
                easing: Easing.linear
            }).start();
        }

        return indicator;
    }

    renderPrompt() {
        if (this.props.refreshing && this.props.scrollStatus === 'EXCEEDED_MIN_PULL_DOWN_DISTANCE') {
            return this.props.topRefreshingPrompt;
        } else if (this.props.refreshing && this.props.scrollStatus === 'EXCEEDED_MIN_PULL_UP_DISTANCE') {
            return this.props.bottomRefreshingPrompt;
        } else if (this.props.scrollStatus === 'EXCEEDED_MIN_PULL_DOWN_DISTANCE') {
            return this.props.topHoldingPrompt;
        } else if (this.props.scrollStatus === 'EXCEEDED_MIN_PULL_UP_DISTANCE') {
            return this.props.bottomHoldingPrompt;
        } else if (this.props.scrollStatus === 'NOT_EXCEEDED_MIN_PULL_UP_DISTANCE') {
            return this.props.bottomPullingPrompt;
        } else if (this.props.scrollStatus === 'NOT_EXCEEDED_MIN_PULL_DOWN_DISTANCE') {
            return this.props.topPullingPrompt;
        }

        return null;
    }

    render() {
        return (
            <View style={[styles.indicatorContainer, this.props.styles.container]}>
                {this.renderIndicatorIcon()}
                <Text style={[styles.prompt, this.props.styles.prompt]}>{this.renderPrompt()}</Text>
            </View>
        );
    }
}

const styles = StyleSheet.create({
    indicatorContainer: {
        alignItems: 'center',
        flexDirection: 'row',
        height: 54,
        paddingLeft: 125
    },
    indicator: {
        width: 24,
        height: 24,
        marginRight: 15,
    },
    prompt: {
        color: '#6e6e6e',
        fontSize: 14,
    }
});

//此库有一些适配问题

results matching ""

    No results matching ""