首頁 > web前端 > js教程 > 在React中使用Native如何實現自訂下拉刷新上拉加載的列表

在React中使用Native如何實現自訂下拉刷新上拉加載的列表

亚连
發布: 2018-06-02 14:37:59
原創
2622 人瀏覽過

本篇文章主要介紹了React Native 自訂下拉刷新上拉加載的清單的範例,現在分享給大家,也給大家做個參考。

在行動裝置開發中清單頁是非常常見的頁面,在React Native中我們一般使用FlatList或SectionList元件實作這些清單檢視。通常列表頁都會有大量的資料需要加載顯示,這時候就用到了分頁加載,因此對於列表組件來說,實現下拉刷新和上拉加載在很多情況下是必不可少的。

這篇文章基於FlatList封裝一個支援下拉刷新和上拉載入的RefreshListView,對原始的FlatList進行封裝之後,再呼叫上拉和下拉刷新就十分方便了。

下拉刷新的實作十分簡單,這裡我們沿用FlatList本身的屬性來實現

#onRefresh— 設定此選項後,則會在列表頭部新增一個標準的RefreshControl控件,以便實現「下拉刷新」的功能。同時你需要正確設定refreshing屬性。

refreshing— bool值,用來控制刷新控制項的顯示與隱藏。刷新完成後設為false。

透過這兩個屬性設定我們就可以實作FlatList頭部的刷新操作,控制項使用預設的樣式,Android和iOS沿著各自系統的元件來顯示。

重點在於上拉載入更多,React Native的清單元件中沒有這個功能,需要我們自己實作。對於上拉加載,通常我們有幾種狀態,這裡我創建一個RefreshState.js檔案存放上拉加載的狀態:

1

2

3

4

5

6

7

export default {

 Idle: 'Idle',        // 初始状态,无刷新的情况

 CanLoadMore: 'CanLoadMore', // 可以加载更多,表示列表还有数据可以继续加载

 Refreshing: 'Refreshing',  // 正在刷新中

 NoMoreData: 'NoMoreData',  // 没有更多数据了

 Failure: 'Failure'     // 刷新失败

}

登入後複製

然後根據這幾種狀態來封裝一個RefreshFooter元件,使其根據不同狀態顯示不同內容,廢話不多說上程式碼:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

import React, {Component} from 'react';

import {View, Text, ActivityIndicator, StyleSheet, TouchableOpacity} from 'react-native';

import RefreshState from './RefreshState';

import PropTypes from 'prop-types';

 

export default class RefreshFooter extends Component {

 

 static propTypes = {

  onLoadMore: PropTypes.func,   // 加载更多数据的方法

  onRetryLoading: PropTypes.func, // 重新加载的方法

 };

  

 static defaultProps = {

  footerRefreshingText: "努力加载中",

  footerLoadMoreText: "上拉加载更多",

  footerFailureText: "点击重新加载",

  footerNoMoreDataText: "已全部加载完毕"

 };

  

 render() {

  let {state} = this.props;

  let footer = null;

  switch (state) {

   case RefreshState.Idle:

    // Idle情况下为null,不显示尾部组件

    break;

   case RefreshState.Refreshing:

    // 显示一个loading视图

    footer =

     <View style={styles.loadingView}>

      <ActivityIndicator size="small"/>

      <Text style={styles.refreshingText}>{this.props.footerRefreshingText}</Text>

     </View>;

    break;

   case RefreshState.CanLoadMore:

    // 显示上拉加载更多的文字

    footer =

     <View style={styles.loadingView}>

      <Text style={styles.footerText}>{this.props.footerLoadMoreText}</Text>

     </View>;

    break;

   case RefreshState.NoMoreData:

    // 显示没有更多数据的文字,内容可以自己修改

    footer =

     <View style={styles.loadingView}>

      <Text style={styles.footerText}>{this.props.footerNoMoreDataText}</Text>

     </View>;

    break;

   case RefreshState.Failure:

    // 加载失败的情况使用TouchableOpacity做一个可点击的组件,外部调用onRetryLoading重新加载数据

    footer =

     <TouchableOpacity style={styles.loadingView} onPress={()=>{

      this.props.onRetryLoading && this.props.onRetryLoading();

     }}>

      <Text style={styles.footerText}>{this.props.footerFailureText}</Text>

     </TouchableOpacity>;

    break;

  }

  return footer;

 }

}

 

const styles = StyleSheet.create({

 loadingView: {

  flexDirection: &#39;row&#39;,

  justifyContent: &#39;center&#39;,

  alignItems: &#39;center&#39;,

  padding: 15,

 },

 refreshingText: {

  fontSize: 12,

  color: "#666666",

  paddingLeft: 10,

 },

 footerText: {

  fontSize: 12,

  color: "#666666"

 }

});

登入後複製

注意,propTypes是我們給RefreshFooter元件定義的給外部呼叫的方法,方法類型需要使用PropTypes來指定,需要安裝facebook的prop-types依賴庫,最好使用yarn add prop-types 安裝,不容易出錯。這裡用作運行時的類型檢查,可以點擊這裡 詳細了解。

defaultProps中我們定義了幾種不同狀態下預設的文字內容,可以在外部傳值進行修改。

接下來就要來實作這個RefreshListView了。首先應該要明確的是,這個RefreshListView要有頭部刷新和尾部刷新的呼叫方法,而具體呼叫資料的方法應該在外部實作。先跟RefreshFooter一樣定義兩個方法:

1

2

3

4

static propTypes = {

 onHeaderRefresh: PropTypes.func, // 下拉刷新的方法,供外部调用

 onFooterRefresh: PropTypes.func, // 上拉加载的方法,供外部调用

};

登入後複製

上面說到頭部的下拉刷新使用FlatList自帶特性實現,我們需要定義一個bool值isHeaderRefreshing來作為refreshing屬性的值,控制頭部顯示與否。同時定義一個isFooterRefreshing來判斷尾部元件的刷新狀態。定義footerState用來設定目前尾部元件的state,作為RefreshFooter的值。

1

2

3

4

5

6

7

8

constructor(props) {

  super(props);

  this.state = {

   isHeaderRefreshing: false, // 头部是否正在刷新

   isFooterRefreshing: false, // 尾部是否正在刷新

   footerState: RefreshState.Idle, // 尾部当前的状态,默认为Idle,不显示控件

  }

 }

登入後複製

render函數如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

render() {

  return (

   <FlatList

    {...this.props}

    onRefresh={()=>{ this.beginHeaderRefresh() }}

    refreshing={this.state.isHeaderRefreshing}

    onEndReached={() => { this.beginFooterRefresh() }}

    onEndReachedThreshold={0.1} // 这里取值0.1(0~1之间不包括0和1),可以根据实际情况调整,取值尽量小

    ListFooterComponent={this._renderFooter}

   />

  )

 }

  

 _renderFooter = () => {

  return (

   <RefreshFooter

    state={this.state.footerState}

    onRetryLoading={()=>{

     this.beginFooterRefresh()

    }}

   />

  )

 };

登入後複製

可以看到上面的程式碼中有beginHeaderRefresh和beginFooterRefresh兩個方法,這兩個方法就是用來呼叫刷新的,但是在刷新之前還有一些邏輯情況需要判斷。例如頭部和尾部不能夠同時刷新,不然資料處理結果可能會受到影響,正在刷新時要防止重複的刷新操作,這些都是要考慮的。這裡我在程式碼中詳細註解了:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

/// 开始下拉刷新

beginHeaderRefresh() {

 if (this.shouldStartHeaderRefreshing()) {

  this.startHeaderRefreshing();

 }

}

 

/// 开始上拉加载更多

beginFooterRefresh() {

 if (this.shouldStartFooterRefreshing()) {

  this.startFooterRefreshing();

 }

}

 

/***

 * 当前是否可以进行下拉刷新

 * @returns {boolean}

 *

 * 如果列表尾部正在执行上拉加载,就返回false

 * 如果列表头部已经在刷新中了,就返回false

 */

shouldStartHeaderRefreshing() {

 if (this.state.footerState === RefreshState.refreshing ||

  this.state.isHeaderRefreshing ||

  this.state.isFooterRefreshing) {

  return false;

 }

 return true;

}

 

/***

 * 当前是否可以进行上拉加载更多

 * @returns {boolean}

 *

 * 如果底部已经在刷新,返回false

 * 如果底部状态是没有更多数据了,返回false

 * 如果头部在刷新,则返回false

 * 如果列表数据为空,则返回false(初始状态下列表是空的,这时候肯定不需要上拉加载更多,而应该执行下拉刷新)

 */

shouldStartFooterRefreshing() {

 if (this.state.footerState === RefreshState.refreshing ||

  this.state.footerState === RefreshState.NoMoreData ||

  this.props.data.length === 0 ||

  this.state.isHeaderRefreshing ||

  this.state.isFooterRefreshing) {

  return false;

 }

 return true;

}

登入後複製

其中startHeaderRefreshing和startFooterRefreshing的邏輯如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

/// 下拉刷新,设置完刷新状态后再调用刷新方法,使页面上可以显示出加载中的UI,注意这里setState写法

startHeaderRefreshing() {

 this.setState(

  {

   isHeaderRefreshing: true

  },

  () => {

   this.props.onHeaderRefresh && this.props.onHeaderRefresh();

  }

 );

}

 

/// 上拉加载更多,将底部刷新状态改为正在刷新,然后调用刷新方法,页面上可以显示出加载中的UI,注意这里setState写法

startFooterRefreshing() {

 this.setState(

  {

   footerState: RefreshState.Refreshing,

   isFooterRefreshing: true

  },

  () => {

   this.props.onFooterRefresh && this.props.onFooterRefresh();

  }

 );

}

登入後複製

在刷新之前,我們需要將頭部或尾部的元件顯示出來,然後再調用外部的資料介面方法。這裡setState這樣寫的好處是state中的值更新完成後才會呼叫箭頭函數中的方法,是有嚴格順序的,如果把this.props.onFooterRefresh && this.props.onFooterRefresh() 寫在setState外部,在在 UI上我們可能看不到頭部的loading或是尾部的努力載入中,介面方法就已經調用完畢了。

最後,在刷新結束後我們還需要呼叫停止刷新的方法,使頭部或尾部元件不再顯示,否則一直是載入中還可能讓人以為是bug。以下來看看停止刷新的方法:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

/**

 * 根据尾部组件状态来停止刷新

 * @param footerState

 *

 * 如果刷新完成,当前列表数据源是空的,就不显示尾部组件了。

 * 这里这样做是因为通常列表无数据时,我们会显示一个空白页,如果再显示尾部组件如"没有更多数据了"就显得很多余

 */

endRefreshing(footerState: RefreshState) {

 let footerRefreshState = footerState;

 if (this.props.data.length === 0) {

  footerRefreshState = RefreshState.Idle;

 }

 this.setState({

  footerState: footerRefreshState,

  isHeaderRefreshing: false,

  isFooterRefreshing: false

 })

}

登入後複製

這裡傳入一個尾部元件狀態的參數是為了更新尾部元件的樣式。同時對資料來源data進行一個判斷,如果為空說明目前沒有數據,可以顯示空白頁面,那麼尾部元件也沒必要顯示了。

以下是我使用RefreshListView實現的豆瓣電影頁面分頁載入的效果圖:

上面是我整理給大家的,希望今後會對大家有幫助。

相關文章:

JS實作的集合去重,交集,並集,差集功能範例

setTimeout時間設定為0詳細解析

vue-cli腳手架config目錄下index.js設定檔的方法

#

以上是在React中使用Native如何實現自訂下拉刷新上拉加載的列表的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板