React Native (pull-down refresh, load more) ultra-simple implementation!

Keywords: React Android iOS less

Let's go straight to our topic today. Let's first look at the results we are going to achieve today.

When we pull down, we display "drop-down refresh status" and "load more" automatically when we slide to the bottom.

Train of thought:
1. Drop-down refresh we use rn's RefreshControl directly.
2. When we slide to the bottom of scrollview or listview, we start displaying the progress bar and load more.

Well, the main problem we have to deal with today is how to judge whether scrollview or listview slides to the bottom:

1. scrollview slides to the top

Everyone who has worked with android knows that in our native scrollview, when our scroll Y of Scrollview is zero, it reaches the top, so it is the same in rn.

2. scrollview slides to the bottom

When the height of scrollview + scrollY >= content Height, it proves that it has slid to the bottom.

Well, with that in mind, we can start. In scroll lview, we can monitor scroll changes:

<ScrollView
                    refreshControl={
                         <RefreshControl
                            refreshing={this.state.isRefreshing}
                            onRefresh={this._onRefresh.bind(this)}
                            tintColor="#ff0000"
                            title="Loading..."
                            titleColor="#00ff00"
                            colors={['#ff0000', '#00ff00', '#0000ff']}
                            progressBackgroundColor="#ffffff"
                          />
                    }
                    onScroll={this._onScroll.bind(this)}
                    scrollEventThrottle={50}
                >

Note that scroll Event Throttle must be given a value in ios, otherwise onScroll calls will be less frequent, affecting our effect.

Then let's see how to write in the _onScroll method.

/**
     * scrollview When sliding
     * @private
     */
    _onScroll(event) {
        if(this.state.loadMore){
            return;
        }
        let y = event.nativeEvent.contentOffset.y;
        let height = event.nativeEvent.layoutMeasurement.height;
        let contentHeight = event.nativeEvent.contentSize.height;
        console.log('offsetY-->' + y);
        console.log('height-->' + height);
        console.log('contentHeight-->' + contentHeight);
        if(y+height>=contentHeight-20){
            this.setState({
                loadMore:true
            });
        }
    }

Is it soeay? When y + height > = contentHeight - 20, this 20 sets an offset for me (children's shoes can be set as required). Then change our state to ok ay.

  render() {
        let self = this;
        return (
            <View style={styles.container}>
                {/*Top navigation bar*/}
                {self._renderNavigator()}
                <ScrollView
                    refreshControl={
                         <RefreshControl
                            refreshing={this.state.isRefreshing}
                            onRefresh={this._onRefresh.bind(this)}
                            tintColor="#ff0000"
                            title="Loading..."
                            titleColor="#00ff00"
                            colors={['#ff0000', '#00ff00', '#0000ff']}
                            progressBackgroundColor="#ffffff"
                          />
                    }
                    onScroll={this._onScroll.bind(this)}
                    scrollEventThrottle={50}
                >
                    {/*Top menu navigation*/}
                    {self._renderTopMenus()}
                    {/*Recommended merchant menu1*/}
                    {self._recommendMerchant()}
                    {/*Recommended merchant menu1*/}
                    {self._recommendMerchant()}
                    {/*Recommended merchant menu1*/}
                    {self._recommendMerchant()}
                    {/*Recommended merchant menu1*/}
                    {self._recommendMerchant()}
                    {/*Recommended merchant menu1*/}
                    {self._recommendMerchant()}
                    {/*Recommended merchant menu1*/}
                    {self._recommendMerchant()}
                    {/*Tail pull-up loads more view s*/}
                    {self._renderLoadMore()}
                </ScrollView>
            </View>
        );
    }
 /**
     * Display loaded view
     * @private
     */
    _renderLoadMore() {
        if (this.state.baseDatas == null || this.state.baseDatas.recommondMerchant == null) {
            return;
        }
        return (
            <LoadingMore
                isLoading={this.state.loadMore}
                onLoading={()=>{
                    alert('fdfdfd');
                }}
            />
        );
    }

LoadingMore.js:

/**
 * @author YASIN
 * @version [React Native PABank V01,17/3/13]
 * @date 17/3/13
 * @description LoadingMore
 */
import React,{Component,PropTypes}from 'react';
import {
    View,
    ActivityIndicator,
    Text,
    TouchableOpacity
}from 'react-native';
import * as ScreenUtils from '../../Util/ScreenUtil';
import {AppBaseColor,AppBaseDimension}from '../../Constant/AppBase';
export default class LoadingMore extends Component {
    static propTypes = {
        isLoading: PropTypes.bool
    }
    static defaultProps = {
        isLoading: false
    }
    // structure
    constructor(props) {
        super(props);
        // Initial state
        this.state = {
            isLoading: props.isLoading
        };
    }

    render() {
        if (this.state.isLoading) {
            return (
                <View
                    style={{flexDirection:'row',alignSelf:'center',alignItems:'center',padding:ScreenUtils.scaleSize(10) }}>
                    <ActivityIndicator
                        size={'small'}
                        color={AppBaseColor.MAIN_COLOR}
                        animating={true}
                        style={{width:ScreenUtils.scaleSize(15),height:ScreenUtils.scaleSize(15)}}
                    />
                    <Text style={{
                        color:AppBaseColor.DESC_COLOR,
                        fontSize:AppBaseDimension.FontSize.DESC,
                        marginLeft:ScreenUtils.scaleSize(15)
                    }}>
                        //Loading...
                    </Text>
                </View>
            );
        } else if(this.props.onLoading){
            return (
                <TouchableOpacity
                    onPress={()=>{
                        this.setState({
                            isLoading:true
                        });
                        this.props.onLoading&&this.props.onLoading()
                    }}
                >
                    <Text style={{
                        color:AppBaseColor.DESC_COLOR,
                        fontSize:AppBaseDimension.FontSize.DESC,
                        alignSelf:'center',
                        padding:ScreenUtils.scaleSize(10)
                    }}>
                        //Click to load more...
                    </Text>
                </TouchableOpacity>
            );
        }
    }

    componentWillReceiveProps(nextProps) {
        this.setState({
            isLoading: nextProps.isLoading
        });
    }
}

ScreenUtil.js:

/**
 * @author YASIN
 * @version [Android YASIN V01, ]
 * @blog http://blog.csdn.net/vv_bug
 * @description
 * Screen Tool Class
 * ui Design benchmark, iphone 6
 * width:750
 * height:1334
 */
import {
    PixelRatio,
}from 'react-native';
import Dimensions from 'Dimensions';
export var screenW = Dimensions.get('window').width;
export var screenH = Dimensions.get('window').height;
var fontScale = PixelRatio.getFontScale();
export var pixelRatio =PixelRatio.get();

export const DEFAULT_DENSITY=2;
const w2 = 750/DEFAULT_DENSITY;
const h2 = 1334/DEFAULT_DENSITY;

export function setSpText(size:Number) {
    var scaleWidth = screenW / w2;
    var scaleHeight = screenH / h2;
    var scale = Math.min(scaleWidth, scaleHeight);
    size = Math.round((size * scale + 0.5) * pixelRatio / fontScale);
    return size;
}
/**
 * Screen adaptation, scaling size
 * @param size
 * @returns {Number}
 * @constructor
 */
export function scaleSize(size:Number) {
    var scaleWidth = screenW / w2;
    var scaleHeight = screenH / h2;
    var scale = Math.min(scaleWidth, scaleHeight);
    size = Math.round((size * scale + 0.5));
    return size/DEFAULT_DENSITY;
}

All right ~~! That's it.

Posted by gszauer on Wed, 17 Apr 2019 18:51:34 -0700