zoukankan      html  css  js  c++  java
  • react-native 自定义 下拉刷新 / 上拉加载更多 组件

    1.封装 Scroller 组件

    /**
     * 下拉刷新/上拉加载更多 组件(Scroller)
     */
    import React, {Component} from 'react';
    import {
      StyleSheet,
      Text,
      View,
      ListView,
      ActivityIndicator,
      RefreshControl,
    } from 'react-native';
     
    export default class Scroller extends Component {
      // 构造函数
      constructor(props) {
        super(props);
        this.state = {
          //
        }
      }
     
      render() {
        const { dataSource, renderRow, isRefreshing } = this.props;
        // console.log(this.props);
     
        return (
          <View style={styles.container}>
            {/*列表数据*/}
            <ListView
              // 数据源
              dataSource={dataSource}
              // 从数据源(dataSource)中接受一条数据,以及它和它所在section的ID
              renderRow={renderRow}
              // 页头与页脚会在每次渲染过程中都重新渲染(允许在ListView底部增加一栏,便于显示加载动画)
              renderFooter={this._renderFooter.bind(this)}
              // 当所有的数据都已经渲染过,并且列表被滚动到距离最底部不足onEndReachedThreshold个像素的距离时调用
              onEndReached={this._fetchMoreData.bind(this)}
              // 调用onEndReached之前的临界值,单位是像素。(预加载)
              onEndReachedThreshold={20}
              // 隐藏右侧滚动条
              showsVerticalScrollIndicator={false}
              // finished warning : in next release ...
              enableEmptySections={true}
              // 自动调整迁移内容
              // 导航栏或标签栏或工具栏不覆盖 Scrollview 内容
              // 去除默认定位间距
              automaticallyAdjustContentInsets={false}
              // 下拉刷新
              refreshControl={
                <RefreshControl
                  // 是否刷新
                  refreshing={isRefreshing}
                  onRefresh={this._onRefresh.bind(this)}
                  tintColor={"#ff6600"}
                  title={"拼命加载中..."}
                />
              }
            />
          </View>
        )
      }
     
      /**
       * 下拉刷新
       */
      _onRefresh() {
        // console.log('下拉刷新');
        if (this.props.isRefreshing || !this._hasMore()) {
          return
        }
        // 向后台发送 '0',告知刷新操作
        this.props.fetchData(0);
      }
     
      /**
       * 加 _ 代表私有方法
       * 上拉加载更多
       */
      _fetchMoreData() {
        // console.log('上拉加载更多');
        /**
         * this._hasMore() 验证还有更多数据
         * isLoadingTail true/false 加载动画(菊花图)
         */
        if (!this._hasMore() || this.props.isLoadingTail) {
          return
        }
        let page = this.props.cachedResults.nextPage;
        this.props.fetchData(page);
      }
     
      /**
       * 验证还有更多数据
       */
      _hasMore() {
        return this.props.cachedResults.items.length !== this.props.cachedResults.items.total;
      }
     
      /**
       * 底部加载动画 及 没有更多数据文本(ListView底部增加一栏,便于显示加载动画)
       */
      _renderFooter() {
        if (!this._hasMore() && this.props.cachedResults.total !== 0) {
          return (
            <View style={styles.loadingMore}>
              <Text style={styles.loadingText}>没有更多了</Text>
            </View>
          )
        }
     
        if (!this.props.isLoadingTail) {
          return (
            <View style={styles.loadingMore}></View>
          )
        }
     
        // 菊花图
        return (
          <ActivityIndicator style={styles.loadingMore}/>
        )
      }
     
    }
     
    // 样式
    const styles = StyleSheet.create({
      container: {
        flex: 1,
        backgroundColor: '#F5FCFF',
      },
      // 菊花图
      loadingMore: {
        marginVertical: 20
      },
      // 文案样式
      loadingText: {
        color: '#777',
        textAlign: 'center'
      }
    });

    2.页面调用

    /**
     * 视频列表页
     */
    import React, {Component} from 'react';
    import {
      StyleSheet,
      Text,
      View,
      ImageBackground,
      ListView,
      TouchableHighlight,
      Alert,
      Dimensions,
      ActivityIndicator,
      RefreshControl,
    } from 'react-native';
    // 下拉刷新/上拉加载更多组件
    import Scroller from '../../components/Scroller';
    // 图标
    import Icon from 'react-native-vector-icons/Ionicons';
    // item 组件
    import CreationItem from '../../components/CreationItem';
    import config from '../../common/config';
    import request from '../../common/request';
     
    let {width} = Dimensions.get("window");
     
    // 缓存列表中所有数据
    let cachedResults = {
      nextPage: 1, // 下一页
      items: [], // listview 数据(视频列表)
      total: 0 // 总数
    };
     
    export default class List extends Component {
      // 构造函数
      constructor() {
        super();
        let ds = new ListView.DataSource({
          // 比较两条数据是否是一样的,来判断数据是否发生改变
          rowHasChanged: (r1, r2) => r1 !== r2
        });
        this.state = {
          dataSource: ds.cloneWithRows([]),
          isLoadingTail: false, // loading?
          isRefreshing: false // refresh?
        }
      }
     
      render() {
        return (
          <View style={styles.container}>
            {/*顶部标题栏*/}
            <View style={styles.header}>
              <Text style={styles.headerTitle}>列表页面</Text>
            </View>
            {/*列表数据*/}
            <Scroller
              // 数据源
              dataSource={this.state.dataSource}
              // 渲染item(子组件)
              renderRow={this._renderRow.bind(this)}
              // 是否可以刷新
              isRefreshing={this.state.isRefreshing}
              // 是否可以加载更多
              isLoadingTail={this.state.isLoadingTail}
              // 请求数据
              fetchData={this._fetchData.bind(this)}
              // 缓存列表数据
              cachedResults={cachedResults}
            />
          </View>
        )
      }
     
      // 生命周期-组件挂载完毕 请求数据
      componentDidMount() {
        this._fetchData(1);
      }
     
      // 请求数据
      _fetchData(page) {
        let that = this;
     
        if (page !== 0) { // 加载更多操作
          this.setState({
            isLoadingTail: true
          });
        } else { // 刷新操作
          this.setState({
            isRefreshing: true
          });
          // 初始哈 nextPage
          cachedResults.nextPage = 1;
        }
     
        request
          .get(config.api.base + config.api.creations, {
            accessToken: 'abc'
          })
          // data 变化的新数据
          .then((data) => {
            if (data.success) {
              // 保存原数据
              let items = cachedResults.items.slice();
              if (page !== 0) { // 加载更多操作
                // 数组拼接
                items = items.concat(data.data);
                cachedResults.nextPage += 1;
              } else { // 刷新操作
                // 数据不变
                items = data.data;
              }
     
              cachedResults.items = items; // 视频列表数据
              cachedResults.total = data.total; // 总数
     
              setTimeout(function () {
                if (page !== 0) { // 加载更多操作
                  that.setState({
                    isLoadingTail: false,
                    dataSource: that.state.dataSource.cloneWithRows(cachedResults.items)
                  });
                } else { // 刷次操作
                  that.setState({
                    isRefreshing: false,
                    dataSource: that.state.dataSource.cloneWithRows(cachedResults.items)
                  });
                }
              }, 1000);
            }
          })
          .catch((error) => {
            if (page !== 0) { // 上拉加载更多操作
              this.setState({
                isLoadingTail: false
              });
            } else {
              this.setState({ // 刷新操作
                isRefreshing: false
              });
            }
            console.error(error);
          });
      }
     
      // 列表 Item
      _renderRow(row) {
        const { navigation } = this.props;
        return (
          <CreationItem
            navigation={navigation}
            key={row.id} // 子组件唯一性
            row={row}
          />
        )
      }
    }
     
    // 样式
    const styles = StyleSheet.create({
      container: {
        flex: 1,
        backgroundColor: '#F5FCFF',
      },
      // 头部样式
      header: {
        paddingTop: 25,
        paddingBottom: 12,
        backgroundColor: '#ee735c',
      },
      // 头部title样式
      headerTitle: {
        color: '#fff',
        fontSize: 16,
        textAlign: 'center',
        fontWeight: '600'
      },
      // 菊花图
      loadingMore: {
        marginVertical: 20
      },
      // 文案样式
      loadingText: {
        color: '#777',
        textAlign: 'center'
      }
    });
  • 相关阅读:
    Persister使用说明
    获取一个目录下的所有文件名称
    bootstrap学习
    bootstrap.文章列表带头像及操作
    初识Lucene.net
    Lucene.net 高亮显示搜索词
    WP7.OnNavigatedTo和OnNavigatedFrom
    SL4.图片下载进度条
    SL4.基本数据验证
    SL4.数据绑定OneWay、OneTime、TwoWay
  • 原文地址:https://www.cnblogs.com/qiyecao/p/9638189.html
Copyright © 2011-2022 走看看