1. 程式人生 > >react native學習筆記13——FlatList上拉載入

react native學習筆記13——FlatList上拉載入

我們可以利用官方元件RefreshControl實現下拉重新整理功能,但React Native官方沒有提供相應的上拉載入的元件,因此在RN中實現上拉載入比下拉重新整理要複雜一點。
雖然沒有直接提供上拉載入的元件,不過我們仍可以通過FlatList的onEndReachedonEndReachedThreshold屬性來實現相應效果。

ActivityIndicator

這裡上拉載入的轉圈效果用ActivityIndicator表現。在開始上拉載入的實現之前先介紹一下官方元件ActivityIndicator——載入指示器。ActivityIndicator的使用很簡單。

    <ActivityIndicator
        animating={true
} color='red' size="large" />

屬性

屬性 型別 描述
animating bool 是否要顯示指示器,預設為true,表示顯示。
color string 滾輪的前景顏色(預設為灰色)。
hidesWhenStopped(ios) bool 在沒有動畫的時候,是否要隱藏指示器(預設為true)。
size enum(‘small’, ‘large’) 指示器的大小。small的高度為20,large為36。

載入頁

根據上述ActivityIndicator屬性的介紹,可以使用ActivityIndicator實現一個簡單的載入頁面:

import React, {Component} from "react";
import {ActivityIndicator,  StyleSheet,  View} from "react-native";

export default class ActivityIndicatorDemo extends Component {
    render() {
        return (
            <View style={styles.container}>
                <ActivityIndicator
                    animating
={true} color='red' size="large" />
</View> ); } } const styles = StyleSheet.create({ container: { flex: 1, flexDirection: 'row', justifyContent: 'center', alignItems: 'center', backgroundColor: '#F5FCFF', }, });

其效果如下:

上拉載入的實現

下面進入正篇——上拉載入的實現
上拉載入一般應用於分頁載入的情況,為了真實的模擬網路請求資料上拉重新整理載入更多的使用場景,這裡使用github提供的api。

思路

當FlatList滑動到底部時,頁面數加一,觸發請求新一頁的網路資料,更新到元件state中的資料來源dataArray中,dataArray也作為FlatList的資料來源data。實現滑動到底部觸發網路請求通過FlatList的onEndReachedonEndReachedThreshold屬性,onEndReached是在當列表被滾動到距離內容最底部不足onEndReachedThreshold的距離時呼叫。

具體實現

全域性變數

const REQUEST_URL = 'https://api.github.com/search/repositories?q=javascript&sort=stars&page=';
let pageNo = 1;//當前第幾頁
let totalPage=5;//總的頁數
let itemNo=0;//item的個數

初始化state

    constructor(props) {
        super(props);
        this.state = {
            isLoading: true,
            //網路請求狀態
            error: false,
            errorInfo: "",
            dataArray: [],
            showFoot:0, // 控制foot, 0:隱藏footer  1:已載入完成,沒有更多資料   2 :顯示載入中
            isRefreshing:false,//下拉控制
        }
    }

網路請求——獲取第n頁資料

    //網路請求——獲取第pageNo頁資料
    fetchData(pageNo) {
        //這個是js的訪問網路的方法
        fetch(REQUEST_URL+pageNo)
            .then((response) => response.json())
            .then((responseData) => {
                let data = responseData.items;
                let dataBlob = [];
                let i = itemNo;

                data.map(function (item) {
                    dataBlob.push({
                        key: i,
                        value: item,
                    })
                    i++;
                });
                itemNo = i;
                console.log("itemNo:"+itemNo);
                let foot = 0;
                if(pageNo>=totalPage){
                    foot = 1;//listView底部顯示沒有更多資料了
                }

                this.setState({
                    //複製資料來源
                    dataArray:this.state.dataArray.concat(dataBlob),
                    isLoading: false,
                    showFoot:foot,
                    isRefreshing:false,
                });
                data = null;
                dataBlob = null;
            })
            .catch((error) => {
                this.setState({
                    error: true,
                    errorInfo: error
                })
            })
            .done();
    }

準備載入元件
在初始化state之後,渲染元件前,請求網路資料。

    componentDidMount() {
        //請求資料
        this.fetchData( pageNo );
    }

渲染元件

    render() {
        //第一次載入等待的view
        if (this.state.isLoading && !this.state.error) {
            return this.renderLoadingView();
        } else if (this.state.error) {
            //請求失敗view
            return this.renderErrorView();
        }
        //載入資料
        return this.renderData();
    }

載入等待頁
利用上面介紹的ActivityIndicator,實現載入等待頁。

    renderLoadingView() {
        return (
            <View style={styles.container}>
                <ActivityIndicator
                    animating={true}
                    color='red'
                    size="large"
                />
            </View>
        );
    }

載入網路請求失敗頁
網路請求失敗,顯示失敗資訊頁。

    renderErrorView() {
        return (
            <View style={styles.container}>
                <Text>
                    Fail
                </Text>
            </View>
        );
    }

載入資料顯示頁

    renderData() {
        return (
            <FlatList
                data={this.state.dataArray}
                renderItem={this._renderItemView}
                ListFooterComponent={this._renderFooter.bind(this)}
                onEndReached={this._onEndReached.bind(this)}
                onEndReachedThreshold={1}
                ItemSeparatorComponent={this._separator}
            />

        );
    }

每個item元件渲染
renderItem根據行資料data渲染每一行的元件。

    //返回itemView
    _renderItemView({item}) {
        return (
            <View>
                <Text style={styles.title}>name: {item.value.name} ({item.value.stargazers_count}
                    stars)</Text>
                <Text style={styles.content}>description: {item.value.description}</Text>
            </View>
        );
    }

尾部元件的渲染
ListFooterComponent為尾部元件的渲染
當showFoot為2時顯示loading的動態效果是用ActivityIndicator來實現的。

     _renderFooter(){
        if (this.state.showFoot === 1) {
            return (
                <View style={{height:30,alignItems:'center',justifyContent:'flex-start',}}>
                    <Text style={{color:'#999999',fontSize:14,marginTop:5,marginBottom:5,}}>
                        沒有更多資料了
                    </Text>
                </View>
            );
        } else if(this.state.showFoot === 2) {
            return (
                <View style={styles.footer}>
                    <ActivityIndicator />
                    <Text>正在載入更多資料...</Text>
                </View>
            );
        } else if(this.state.showFoot === 0){
            return (
                <View style={styles.footer}>
                    <Text></Text>
                </View>
            );
        }
    }

上拉載入
上拉載入的關鍵onEndReached,當列表被滾動到距離內容最底部不足onEndReachedThreshold的距離時呼叫。注意:onEndReachedThreshold的值不是畫素單位而是比值,例如,0.5表示距離內容最底部的距離為當前列表可見長度的一半時觸發。

    _onEndReached(){
        //如果是正在載入中或沒有更多資料了,則返回
        if(this.state.showFoot != 0 ){
            return ;
        }
        //如果當前頁大於或等於總頁數,那就是到最後一頁了,返回
        if((pageNo!=1) && (pageNo>=totalPage)){
            return;
        } else {
            pageNo++;
        }
        //底部顯示正在載入更多資料
        this.setState({showFoot:2});
        //獲取資料
        this.fetchData( pageNo );
    }
}

分隔線
ItemSeparatorComponent行與行之間的分隔線元件,不會出現在第一行之前和最後一行之後。

    _separator(){
        return <View style={{height:1,backgroundColor:'#999999'}}/>;
    }

效果圖如下:

最後附上完整程式碼:

import React, {Component} from "react";
import {ActivityIndicator, FlatList, StyleSheet, Text, View} from "react-native";

const REQUEST_URL = 'https://api.github.com/search/repositories?q=javascript&sort=stars&page=';
let pageNo = 1;//當前第幾頁
let totalPage=5;//總的頁數
let itemNo=0;//item的個數
export default class LoadMoreDemo extends Component {
    constructor(props) {
        super(props);
        this.state = {
            isLoading: true,
            //網路請求狀態
            error: false,
            errorInfo: "",
            dataArray: [],
            showFoot:0, // 控制foot, 0:隱藏footer  1:已載入完成,沒有更多資料   2 :顯示載入中
            isRefreshing:false,//下拉控制
        }
    }

    //網路請求——獲取第pageNo頁資料
    fetchData(pageNo) {
        //這個是js的訪問網路的方法
        fetch(REQUEST_URL+pageNo)
            .then((response) => response.json())
            .then((responseData) => {
                let data = responseData.items;
                let dataBlob = [];
                let i = itemNo;

                data.map(function (item) {
                    dataBlob.push({
                        key: i,
                        value: item,
                    })
                    i++;
                });
                itemNo = i;
                console.log("itemNo:"+itemNo);
                let foot = 0;
                if(pageNo>=totalPage){
                    foot = 1;//listView底部顯示沒有更多資料了
                }

                this.setState({
                    //複製資料來源
                    dataArray:this.state.dataArray.concat(dataBlob),
                    isLoading: false,
                    showFoot:foot,
                    isRefreshing:false,
                });
                data = null;
                dataBlob = null;
            })
            .catch((error) => {
                this.setState({
                    error: true,
                    errorInfo: error
                })
            })
            .done();
    }

    componentDidMount() {
        //請求資料
        this.fetchData( pageNo );
    }

    //載入等待頁
    renderLoadingView() {
        return (
            <View style={styles.container}>
                <ActivityIndicator
                    animating={true}
                    color='red'
                    size="large"
                />
            </View>
        );
    }

    //載入失敗view
    renderErrorView() {
        return (
            <View style={styles.container}>
                <Text>
                    Fail
                </Text>
            </View>
        );
    }

    //返回itemView
    _renderItemView({item}) {
        return (
            <View>
                <Text style={styles.title}>name: {item.value.name}</Text>
                <Text style={styles.content}>stars: {item.value.stargazers_count}</Text>
                <Text style={styles.content}>description: {item.value.description}</Text>
            </View>
        );
    }

    renderData() {
        return (

            <FlatList
                data={this.state.dataArray}
                renderItem={this._renderItemView}
                ListFooterComponent={this._renderFooter.bind(this)}
                onEndReached={this._onEndReached.bind(this)}
                onEndReachedThreshold={1}
                ItemSeparatorComponent={this._separator}
            />

        );
    }

    render() {
        //第一次載入等待的view
        if (this.state.isLoading && !this.state.error) {
            return this.renderLoadingView();
        } else if (this.state.error) {
            //請求失敗view
            return this.renderErrorView();
        }
        //載入資料
        return this.renderData();
    }
    _separator(){
        return <View style={{height:1,backgroundColor:'#999999'}}/>;
    }
    _renderFooter(){
        if (this.state.showFoot === 1) {
            return (
                <View style={{height:30,alignItems:'center',justifyContent:'flex-start',}}>
                    <Text style={{color:'#999999',fontSize:14,marginTop:5,marginBottom:5,}}>
                        沒有更多資料了
                    </Text>
                </View>
            );
        } else if(this.state.showFoot === 2) {
            return (
                <View style={styles.footer}>
                    <ActivityIndicator />
                    <Text>正在載入更多資料...</Text>
                </View>
            );
        } else if(this.state.showFoot === 0){
            return (
                <View style={styles.footer}>
                    <Text></Text>
                </View>
            );
        }
    }

    _onEndReached(){
        //如果是正在載入中或沒有更多資料了,則返回
        if(this.state.showFoot != 0 ){
            return ;
        }
        //如果當前頁大於或等於總頁數,那就是到最後一頁了,返回
        if((pageNo!=1) && (pageNo>=totalPage)){
            return;
        } else {
            pageNo++;
        }
        //底部顯示正在載入更多資料
        this.setState({showFoot:2});
        //獲取資料
        this.fetchData( pageNo );
    }
}

const styles = StyleSheet.create({
    container: {
        flex: 1,
        flexDirection: 'row',
        justifyContent: 'center',
        alignItems: 'center',
        backgroundColor: '#F5FCFF',
    },
    title: {
        fontSize: 15,
        color: 'blue',
    },
    footer:{
        flexDirection:'row',
        height:24,
        justifyContent:'center',
        alignItems:'center',
        marginBottom:10,
    },
    content: {
        fontSize: 15,
        color: 'black',
    }
});

相關推薦

react native學習筆記13——FlatList載入

我們可以利用官方元件RefreshControl實現下拉重新整理功能,但React Native官方沒有提供相應的上拉載入的元件,因此在RN中實現上拉載入比下拉重新整理要複雜一點。 雖然沒有直接提供上拉載入的元件,不過我們仍可以通過FlatList的onEnd

React Native學習筆記之--ListView和RefreshControl實現下重新整理

React Native學習筆記之–ListView和RefreshControl實現下拉重新整理 今天利用React Native中的ListView來實現原生開發中的UITableView(Android中就叫ListView)的介面效果。 資料數利用Ch

React-Native 學習筆記-Android開發平臺-開發環境搭建

環境變量 最新版 下載 and 系統 系統環境變量 新版本 開發環境 studio 詳細步驟請查看官網對應文檔,BUT,有些註意事項請註意! 1,優先安裝Node.js,因為後面可以使用npm安裝軟件, 2,註意不要使用CNPM!!!!!!!!! 3,Android

React Native學習筆記 -- 開發環境搭建

ebo 安裝完成 原因 包管理工具 chown iss 運行 遇到 命令 工欲善其事,必先利其器。這次主要介紹mac osx下React Native的開發環境的搭建。 homebrew mac上的包管理工具,用於安裝nodejs和其他一些工具軟件,在terminal輸入下

react native學習筆記24——Modal實現自定義彈出對話方塊

前言 上一篇文章介紹React Native系統提供的兩個彈出框的api——Alert與AlertIOS,Alert可以在雙平臺通用,但是隻能展示資訊量有限功能單一的文字對話方塊。AlertIOS比Alert稍微豐富一點,可以展示供使用者輸入的對話方塊,但只能

React Native學習筆記2:Android環境搭建

背景 各位童鞋有木有感覺官方文件很坑啊,根據官網的描述,首先在chocolate就直接卡死了,VPN沒什麼卵用,於是逐個去官網下載,直到昨天才發現不用VPN也可以下!公司是windows環境,這裡就先用windows搭建。 因為本身是移動開發者,所以

React Native 學習筆記十三(原生模組之Toast)

 在學習官網上的Toast 的過程中 出現很多的坑  廢話就不說了 官網上都有 官網講解 實現思路 : 我們之前已經將react-native 嵌入原生了 那麼 我們就在之前的基礎上進行修改就好了    建立ToastUtils.java 繼承ReactContextBas

React-Native學習筆記之:導航器Navigator實現頁面間跳轉

Navigator用來實現不同頁面的切換,想設定Navigator,必須確定一個或多個呼叫routes物件,去定義每個場景。 還可以利用renderScene方法,導航欄可以根據指定的路由來渲染場景。

React Native 學習筆記(二)

坑一,環境好了,但是因為專案需求經常要安裝一些三方庫,xcode-select: error: tool ‘xcodebuild’ requires Xcode, but active developer directory ‘/Library/Develope

React Native學習筆記一之搭建開發環境

因為專案需要,今天開始正式學習React Native,先來搭建個開發環境 忐忑的心情 因為專案比較急,而且客戶要求使用React Native開發,只能先學點基礎然後在專案中使用的時候,邊做邊學了,在保證工期的前提下,進擊的程式猿, go,go,go!

React Native學習筆記之--向原生應用中整合RN頁面

React Native學習筆記之–向原生應用中整合RN頁面 根據在官方文件的學習要向已有的原生專案中新增RN元件最重要的就是以下幾步: 1.Understand what React Native components you want to in

react native 學習筆記----將react native嵌入到Android原生應用

不僅可以在react native 的js介面和現有工程的介面之間跳轉,而且可以把js寫的介面當成一個控制元件,嵌入到現有的activity,作為原生介面的一部分使用。 第一節:按照官方的例子,把js寫頁面放在一個activity,在原生應用裡啟動該activity。 開

React Native學習安卓手機的返回鍵BackAndroid

使用 React Native開發,iOS搞完,開始適配安卓,由於木有接觸過安卓,所以碰到了很多問題,第一個問題,安卓的返回鍵BackAndroid問題,我寫了一個工具類,來搞定,其中用到了java原

React-Native學習筆記——正確整合到現有Android工程中

背景 我們可能需要將react-native整合到已有工程的某個module中,而不是從頭建立一個新工程。下面記錄了筆者一個demo的整合過程。 已有工程結構 下圖中,app為application型別module,rntrial為library型別的mo

React Native 學習筆記(一)--init 專案 和 執行專案

宣告:此篇blog是在Windows環境下開發Android專案的學習筆記,最近也是在網上翻找資料發現,網上的資源基本上都是Mac環境下的,而且大部分的資料都是關於React Native + Web / Service 的,關於android的學習資源不多,因此也就想通過

react native 學習筆記-----理解redux的一個極其簡單例子

'use strict'; import React, { Component, PropTypes} from 'react'; import {   StyleSheet,   Text,   View,   Image,   Button,   AppRegistry,   TouchableHighl

react native學習筆記15——Picker、Switch、Slider

本文將介紹三個常用的元件Picker、Switch、Slider,它們都是官方提供的,並且均可以在android與ios渲染對應的原生元件。這三個元件的使用很簡單,在實戰開發中也很常見,因此這裡放在一起介紹。 Picker選擇器 Picker選擇器,通常

React-Native學習筆記——技術棧及簡介

推薦的技術棧順序清單 1、阮一峰es6: http://es6.ruanyifeng.com/   es6中的新特性是後續內容的基礎,重點內容有let關鍵字、解構賦值、建構函式和原型鏈、Promise物件、yield關鍵字、Generator函式、aysnc/await等

React Native學習筆記(一)Mac OS X下React Native的環境搭建

本文介紹Mac OS X系統下的React Native環境搭建過程。 1.環境要求: 1) Mac OS X作業系統 2) Xcode6.4或以上版本 3) Node.js4.0或以上版本 4) watchman和flow 2.安裝過程 1) N

React Native學習筆記之--元件之間資料的傳遞和跳轉

React Native學習筆記之–元件之間資料的傳遞和跳轉 自定義屬性的定義方式和傳遞 假定元件ComponentA中的自定義屬性為 static props = { tit