FlatList组件学习和封装

FlatList组件学习和封装

是一个用于呈现简单的平面列表的高性能组件,支持下面功能:

  • 跨平台
  • 支持水平
  • 支持可配置的可视性回调
  • 支持头部
  • 支持尾部
  • 支持下拉刷新
  • 支持上来加载
  • 支持跳转到指定行 他是继承自ScrollView以及VirtualizedList的,所以具有他们二者的props;

简单例子

    render(){
        return 
            'a'}, {key: 'b'}]}
                renderItem={({item}) => {item.key}}
            />

        
    }
复制代码

其中包含了最重要两个组件datarenderItem,data是数据list,是一个一个对象组合而成的,renderItem是条目。

FlatList重要方法

1 renderItem 他是一个方法,用于渲染具体的Item,他回调有几个参数,定义如下

renderItem(item,index,separators){

}
复制代码

需要注意的是我们使用的时候一般需要进行解构赋值去取item的单个内容,下面谈到封装的时候再给例子。

2 data 他是FlastList的数据源,是一个数组

3 ListEmptyComponent 需要返回一个Component,当FlatList数据为空的时候的组件

4 ListFooterComponent 需要返回一个Component,FlatList的footer组件

5 ListHeaderComponent 需要返回一个Component,FlatList的头部组件,需要注意他不是刷新的那个组件,只是一个不同于普通item的头部组件

6 horizontal 一个布尔值,表明 是垂直的还是水平的FlatList,true是水平,false是垂直。

7 keyExtractor 定义是

(item: object, index: number) => string;
复制代码

指定一个function,返回item的index,相当于Android的adapter的getIndex()方法,返回一个独立Item的唯一标识,需要返回一个index

8 numColumns 是一个number,表明该FlatList是几列。

9 onEndReached 当FlatLst到达底部的时候的回调

10 onRefresh FlatList触发刷新时候的回调

11 refreshing 控制是否处于刷新状态

12 ItemSeparatorComponent 需要返回一个Component,作为item之间的分割线

13 FlatList提供的一些scroll方法,比如滚动到底部,滚动到具体item,滚动多少距离等。

scrollToEnd //滚动到底部
scrollToIndex //滚动到第几个item
scrollToItem //滚动到某个item 
scrollToOffset //滚动多少距离
recordInteraction //告诉列表滚动发送了,会去调用viewability的计算。
flashScrollIndicators //随时显示滚动指示器
复制代码

封装FlatList

对于FlatList的刷新样式,我们能够定义或者是改造的可行性比较难,他的样式一般是比较固定,我们,假如需要自定义刷新的组件,可以参考我给出的推荐学习。

对于FlatList的封装,整体需要做到开闭原则,我们有几点需求需要明确:

  1. 提供刷新+加载
  2. 可分别设置是否刷新+加载是否可用
  3. 提供样式外部可定义以及一套默认样式
  4. 提供多种列表状态,比如刷新中,加载中,加载完成,加载失败,空数据等
  5. 提供一个onRequest(isRefresh:boolean)方法给外部,进行刷新或者加载处理
  6. 对于一些方法,提供默认配置,但是外部也可以进行修改。
  • 定义FlatList的状态,默认props,styles以及需要的state
//state
export const State = {
  NORMAL: 0,//正常状态
  REFRESHING: 1,//刷新中
  LOADING: 2,//正在加载
  LOAD_END: 3,//上拉加载完成
  ERROR: 4,//上拉加载发生错误
  NO_DATA: 5,//无数据情况
};

/**
 * 默认样式
 */
const styles = StyleSheet.create({
  //底部默认样式
  footerContainer: {
    flex: 1,
    flexDirection: "row",
    justifyContent: "center",
    alignItems: "center",
    padding: 10,
    height: 44,
  },
  footerText: {
    fontSize: 14,
    color: "#555555"
  }
});

//props+state
    static defaultProps = {
    loadingText: "数据加载中...",
    loadErrorText: "点击重新加载...",
    loadEndText: "已加载全部数据",
    loadEmptyText: "暂时没有相关数据",
    requestState: State.NORMAL,
    footerContainer: {},
    footerText: {},
    data: [],
    id: "flat_list",
    onRequest: (isRefresh) => {
    },
  };
  constructor(props) {
    super(props);
    //是否刷新/加载可用,外部可以通过调用方法设置,默认都可以
    this.state = {
      enableLoadMore: true,
      enableRefresh: true,
    };
  }
复制代码
  • 外部设置是否可用方法
  /**
   * 不会显示顶部可以刷新的UI
   * @param enableLoad
   */
  setEnableLoad(enableLoad) {
    this.setState({
      enableLoad: enableLoad,
    });
  }
  /**
   * 他是不会显示底部刷新的UI的
   * @param enableRefresh
   */
  setEnableRefresh(enableRefresh) {
    this.setState({
      enableRefresh: enableRefresh,
    });
  }
复制代码
  • 数据加载方法
  /**
   * 刷新触发
   * @private
   */
  _onRefresh = () => {
    if (this._enableRefresh()) {
      this.props.onRequest && this.props.onRequest(true);
    }
  };
  /**
   * 是否可以顶部刷新
   * 当前需要 非刷新,而且也不是正在加载
   * @returns {boolean}
   */
  _enableRefresh = () => {
    return !(this.props.requestState === State.REFRESHING || this.props.requestState === State.LOADING);
  };
  _onEndReached = () => {
    if (this._enableLoad()) {
      this.props.onRequest && this.props.onRequest(false);
    }
  };
  /**
   * 是否可以加载,当前数据不能是0(因为进入的时候必须是refresh获取的数据显示)
   * @returns {boolean}
   */
  _enableLoad = () => {
    let { requestState, data } = this.props;
    if (data.length === 0) {
      return false;
    }
    return requestState === State.NORMAL;
  };
  /**
   * 刷新或加载
   * @param isRefresh
   * @private
   */
  _reRequest = (isRefresh) => {
    //回调外部方法
    this.props.onRequest && this.props.onRequest(isRefresh);
  };
  _keyExtractor = (item, index) => {
    const { keyExtractor } = this.props;
    if (keyExtractor) {
      return keyExtractor(item, index);
    }
    return index.toString();
  };
复制代码
  • Item的唯一标识以及默认的分割线
  _keyExtractor = (item, index) => {
    const { keyExtractor } = this.props;
    if (keyExtractor) {
      return keyExtractor(item, index);
    }
    return index.toString();
  };

_separator = () => {
    const { separator } = this.props;
    if (separator) {
      return separator();
    }
    return "#ededed",
      marginLeft: 10,
      marginRight: 10
    }}/>;
  };
复制代码
  • Footer,footer对于不同的FlatList状态会返回不同的Component
/**
   * 渲染底部
   * @returns {*}
   */
  _renderFooter = () => {
    let footer = null;
    let footerContainerStyle = [styles.footerContainer, this.props.footerContainer];
    let footerTextStyle = [styles.footerText, this.props.footerText];
    let { loadingText, loadErrorText, loadEndText, loadEmptyText } = this.props;
    const hasData = this.props.data && this.props.data.length > 0;
    switch (this.props.requestState) {
      case State.NORMAL:
        footer = ();
        break;
      case State.ERROR: {
        //是否有数据
        footer = hasData ? (
          
            {loadErrorText}
          
        ) : ();
        break;
      }
      case State.NO_DATA: {
        footer = ;
        break;
      }
      case State.LOADING: {
        footer = (
          
            "small" color="#888888"/>
            {loadingText}
          
        );
        break;
      }
      case State.LOAD_END: {
        footer = (
          
            {loadEndText}
          
        );
        break;
      }
    }
    return footer;
  };
复制代码

其中Empty是空数据的组件,另外独立定义了他的Component

class EmptyData extends Component {
  static defaultProps = {
    tips: "暂无数据",
  };
  _onPress = () => {
    const { onPress } = this.props;
    if (onPress) {
      onPress(true);
    }
  };
  render() {
    return (
      
        "center",
          justifyContent: "center"
        }}>
          "contain"
            }}
            source={require("../../img/pic_empty_data.png")}
          />
          {this.props.tips}
        
      
    );
  }
}
复制代码
  • render方法
/**
   * 渲染
   * @returns {*}
   */
  render() {
    let {
      renderItem = () => {
      }
    } = this.props;
    return (
      
    );
  }
}
复制代码

这样子我们就定义了一个完整的PullLoadComponent。

使用

我们用玩Android开发的Api,这里感谢玩Android提供的Api接口。

const API = "http://www.wanandroid.com/article/list/";
export default class FlatListDemoPage extends Component {
  static navigationOptions = {
    // headerTitle: 'first',
    title: "FlatListDemoPage",
  };
  constructor(props) {
    super(props);
    this.state = {
      requestState: State.NORMAL,
      data: []
    };
    this.currentPage = 0;
  }
  componentDidMount() {
    this._request(true);
  }
  _request = (isRefresh) => {
    this.currentPage = isRefresh ? 0 : this.currentPage + 1;
    this.setState({ requestState: isRefresh ? State.REFRESHING : State.LOADING });
    //发起请求
    fetch(API + this.currentPage + "/json") // 返回一个Promise对象
      .then((res) => {
        return res.json();
      })
      .then((res) => {
        const { data } = res;
        const { datas } = data;
        this._setData(datas);
      })
      .catch(e => {
        //加载失败
        console.log(e);
        this.setState({ requestState: State.ERROR });
      });
  };
  _setData = (data, isRefresh) => {
    if (data && data.length > 0) {
      //判断一下是否还有下一页,因为一页最多20条,不满足则是无法去加载更多了
      this.setState({
        requestState: data.length >= 20 ? State.NORMAL : State.LOAD_END,
        data: isRefresh ? data : this.state.data.concat(data)
      });
    } else {
      //已经没有数据了,需要对footer进行处理
      if (this.currentPage === 0) {
        //第一页没有数据,那么就是当前接口无数据
        this.setState({
          requestState: State.NO_DATA,
          data: []
        });
      } else {
        //不是第一页,新页返回空,就是接下来没有数据了
        this.setState({
          requestState: State.LOAD_END,
          data: this.state.data
        });
      }
    }
  };
  _renderItem = ({ item }) => {
    const { title } = item;
    return "black",
      textAlign: "center",
    }}>{title};
  };
  render() {
    console.log("requestState=" + this.state.requestState);
    return (
      
         {
            this.flat_list = flat_list;
          }}
          onRequest={this._request}
          data={this.state.data}
          requestState={this.state.requestState}
          renderItem={this._renderItem}
        />
      
    );
  }
}
复制代码

Demo地址: ReactNativeDemo

推荐学习

  • 官网
  • React Native 之自定义下拉刷新

你可能感兴趣的:(移动开发,json,ui)