zoukankan      html  css  js  c++  java
  • React Native常用组件之ListView

    1. ListView常用属性

    • ScrollView 相关属性样式全部继承

    • dataSource ListViewDataSource 设置ListView的数据源

    • initialListSize number
      设置ListView组件刚刚加载的时候渲染的列表行数,用这个属性确定首屏或者首页加载的数量,而不是花大量的时间渲染加载很多页面数据,提高性能。

    • onChangeVisibleRows function (visibleRows,changedRows)=>void。
      当可见的行发生变化的时候回调该方法。

    • onEndReachedThreshold number
      当偏移量达到设置的临界值调用onEndReached

    • onEndReached function

      当所有的数据项行被渲染之后,并且列表往下进行滚动。一直滚动到距离底部onEndReachedThredshold设置的值进行回调该方法。原生的滚动事件进行传递(通过参数的形式)。

    • pageSize number 每一次事件的循环渲染的行数

    • removeClippedSubviews bool

      该属性用于提供大数据列表的滚动性能。该使用的时候需要给每一行(row)的布局添加over:'hidden'样式。该属性默认是开启状态。

    • renderFooter function 方法 ()=>renderable

      在每次渲染过程中头和尾总会重新进行渲染。如果发现该重新绘制的性能开销比较大的时候,可以使用StaticContainer容器或者其他合适的组件。

    • renderHeader function 方法

      在每一次渲染过程中Footer(尾)该会一直在列表的底部,header(头)该会一直在列表的头部,用法同上。

    • renderRow function (rowData,sectionID,rowID,highlightRow)=>renderable
      该方法有四个参数,其中分别为数据源中一条数据,分组的ID,行的ID,以及标记是否是高亮选中的状态信息。

    • renderScrollComponent function

      方法 (props)=>renderable 该方法可以返回一个可以滚动的组件。默认该会返回一个ScrollView

    • renderSectionHeader function (sectionData,sectionID)=>renderable

      如果设置了该方法,这样会为每一个section渲染一个粘性的header视图。该视图粘性的效果是当刚刚被渲染开始的时候,该会处于对应的内容的顶部,然后开始滑动的时候,该会跑到屏幕的顶端。直到滑动到下一个section的header(头)视图,然后被替代为止。

    • renderSeparator function

      (sectionID,rowID,adjacentRowHighlighted)=>renderable
      如果设置该方法,会在被每一行的下面渲染一个组件作为分隔。除了每一个section分组的头部视图前面的最后一行。

    • scrollRenderAheadDistance number

      进行设置当该行进入屏幕多少像素以内之后就开始渲染该行

    2. ListView的高阶特性

    • ListView同样支持一些高级特性,包括设置每一组的粘性的头部(类似于iPhone)、支持设置列表的header以及footer视图、当数据列表滑动到最底部的时候支持onEndReached方法回调、设备屏幕列表可见的视图数据发生变化的时候回调onChangeVisibleRows以及一些性能方面的优化特性。

    • ListView设计的时候,当需要动态加载非常大的数据的时候,下面有一些方法性能优化的方法可以让我们的ListView滚动的时候更加平滑:

      • 只更新渲染数据变化的那一行 ,rowHasChanged方法会告诉ListView组件是否需要重新渲染当前那一行。
      • 选择渲染的频率,默认情况下面每一个event-loop(事件循环)只会渲染一行(可以同pageSize自定义属性设置)。这样可以把大的工作量进行分隔,提供整体渲染的性能。

    3. Demo1 - ListView的简单使用

    3.1 代码

    /**
     * Sample React Native App
     * https://github.com/facebook/react-native
     * @flow
     */
    
    import React, {Component} from 'react';
    import {
      AppRegistry,
      StyleSheet,
      Text,
      View,
      Image,
      ListView,
      TouchableOpacity,
      AlertIOS,
    } from 'react-native';
    
    var Dimensions = require('Dimensions');
    var {width, height} = Dimensions.get('window');
    // 引入数据文件
    var models = require("./Wine.json");
    
    var rn0910ListViewTest01 = React.createClass({
    
      /**
       * 生命周期,不可更改的属性在这里
       * @returns {{}}
       */
      getDefaultProps() {
        return {}
      },
      /**
       * 生命周期,状态机在这里
       * @returns {{}}
       */
      getInitialState() {
        // 创建数据源   rowHasChanged方法决定了ListView是否重新渲染当前这一行
        var ds = new ListView.DataSource({
          rowHasChanged: (r1, r2) => {
            r1 !== r2
          }
        });
        return {
          // 数据源中的数据
          dataSource: ds.cloneWithRows(models)
        }
      },
      /**
       * 生命周期,复杂的操作在这里
       */
      componentDidMount() {
    
      },
      /**
       * 生命周期,渲染
       * @returns {XML}
       */
      render() {
        return (
          <ListView
            dataSource={this.state.dataSource} // 指定数据源
            renderRow={this.renderRow} // 渲染每一行
          />
        );
      },
      /**
       * ListView根据数据源的数据进行渲染
       * @param rowData 每一项的数据
       * @param sectionID 组号
       * @param rowID 行号
       * @param highlightRow
       * @returns {XML}
       */
      renderRow(rowData, sectionID, rowID, highlightRow) {
        return (
          <TouchableOpacity 
            activeOpacity={0.7} 
            onPress={() => this.cellDidClick(rowID, rowData)}
          >
            <View style={styles.wineCell}>
              <Image style={styles.icon} source={{uri: rowData.image}}/>
              <View style={styles.titleContainer}>
                <Text style={styles.title}>{rowData.name}</Text>
                <Text style={styles.subTitle}>${rowData.money}</Text>
              </View>
            </View>
          </TouchableOpacity>
        );
      },
    
      cellDidClick(rowID, rowData) {
        alert("点击了" + rowID + rowData.name);
      }
    });
    
    const styles = StyleSheet.create({
      container: {
        flex: 1,
        justifyContent: 'center',
        alignItems: 'center',
        backgroundColor: '#F5FCFF',
        paddingTop: 20
      },
      wineCell: {
        flexDirection: "row",
        borderBottomWidth: 1,
        borderBottomColor: '#eee',
        paddingLeft: 10,
        paddingTop: 10,
        paddingBottom: 10,
        backgroundColor: 'white'
      },
      icon: {
         60,
        height: 60,
      },
      titleContainer: {
        flexDirection: "column",
        justifyContent: 'space-between'
      },
      title: {
        fontSize: 15,
        fontWeight: 'bold',
         width - 60,
        paddingLeft: 10,
        paddingRight: 10
      },
      subTitle: {
        fontSize: 15,
        marginLeft: 10,
      }
    });
    
    AppRegistry.registerComponent('rn0910ListViewTest01', () => rn0910ListViewTest01);
    
    

    3.2 效果图

    4. ListView之九宫格布局

      listViewContentStyle: {
        // ListView实现九宫格布局,主要是这俩属性
        flexDirection: 'row',
        flexWrap: 'wrap'
      },
      cellStyle: {
        alignItems: 'center',
        // 每一项设置宽高
         cellWH,
        height: cellWH,
        marginLeft: hMargin,
        marginTop: tMargin
      },
    

    4.1 代码

    /**
     * Sample React Native App
     * https://github.com/facebook/react-native
     * @flow
     */
    
    import React, {Component} from 'react';
    import {
      AppRegistry,
      StyleSheet,
      Text,
      View,
      ListView,
      Image,
      TouchableOpacity,
      AlertIOS
    } from 'react-native';
    
    // 引入json文件
    var models = require("./shareData.json");
    // 获取屏幕宽度
    var Dimensions = require('Dimensions');
    var screen_Width = Dimensions.get('window').width;
    
    var col = 3; // 列数
    var cellWH = 100; // 每项宽高
    var tMargin = 25; // 行 顶间距
    var hMargin = (screen_Width - cellWH * col) / (col + 1); // 每项之间的间距
    
    var rn0912ListViewTest02 = React.createClass({
      /**
       * 不可修改的属性
       * @returns {{}}
       */
      getDefaultProps() {
        return {}
      },
      /**
       * 状态机
       */
      getInitialState() {
        var ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
        return {
          dataSource: ds.cloneWithRows(models.data)
        }
      },
      /**
       * 渲染
       * @returns {{}}
       */
      render() {
        return (
          <ListView
            dataSource={this.state.dataSource}
            renderRow={this.renderRow}
            contentContainerStyle={styles.listViewContentStyle}
          />
        )
      },
      /**
       * 操作
       */
      componentDidMount() {
    
      },
      renderRow(rowData) {
        return (
          <TouchableOpacity
            activeOpacity={0.8}
            onPress={() => {
              alert("点击分享到" + rowData.title)
            }}
          >
            <View style={styles.cellStyle}>
              <Image style={styles.iconStyle} source={{uri: rowData.icon}}/>
              <Text style={styles.nameStyle}>{rowData.title}</Text>
            </View>
          </TouchableOpacity>
        );
      }
    });
    
    const styles = StyleSheet.create({
      container: {
        flex: 1,
        justifyContent: 'center',
        alignItems: 'center',
        backgroundColor: '#F5FCFF',
      },
      listViewContentStyle: {
        // ListView实现九宫格布局,主要是这俩属性
        flexDirection: 'row',
        flexWrap: 'wrap'
      },
      cellStyle: {
        alignItems: 'center',
        // 每一项设置宽高
         cellWH,
        height: cellWH,
        marginLeft: hMargin,
        marginTop: tMargin
      },
      iconStyle: {
         80,
        height: 80,
      },
      nameStyle: {
        fontSize: 14
      }
    });
    
    AppRegistry.registerComponent('rn0912ListViewTest02', () => rn0912ListViewTest02);
    
    

    4.2 效果图

    5. ListView黏性sectionHeader

    5.1 技术点分析

    • 如何实现滚动时每个sectionHeader会吸顶?

      在ListView中要实现sticky,需要使用cloneWithRowsAndSections方法,将dataBlob(object),sectionIDs(array),rowIDs(array)三个值传进去.

    dataBlob

    dataBlob包含ListView所需的所有的数据(sectionHeader 和 rows),在ListView渲染数据时,使用getSectionData 和 getRowData 来渲染每一行数据. dataBlob的 key 值包含sectionID + rowID

    sectionIDs

    sectionIDs 用语表示每组section

    rowIDs 二维数组

    rowIDs 用于描述每个section里的每行数据的位置及是否需要渲染. 在ListView渲染时,会先遍历 rowIDs 获取到对应的 dataBlob 数据

    模拟对应的数据结构

    在 DataSource 中, 设置ListView获取 row 和 section 的方法

      getInitialState() {
    
        var getSectionHeaderData = (dataBlob, sectionID) => {
          return dataBlob[sectionID];
        }
        var getRowData = (dataBlob, sectionID, rowID) => {
          return dataBlob[sectionID + ":" + rowID];
        }
    
        return {
          // 设置数据源,数据庞大,在
          dataSource: new ListView.DataSource({
            getSectionHeaderData: getSectionHeaderData, // 获取组数据
            getRowData: getRowData, // 获取行数据
            rowHasChanged: (r1, r2) => {
              r1 !== r2
            }, // 什么时候创建行
            sectionHeaderHasChanged: (s1, s2) => {
              s1 !== s2
            } // 什么时候创建组
          })
        };
      },
    

    刷新状态机,将数据传入到ListView中

    this.setState({
     dataSource: this.state.dataSource.cloneWithRowsAndSections(dataBlob, sectionIDs, rowIDs)
    });
    

    ListView中不仅要renderRow 还要 renderSectionHeader

       <ListView
         dataSource={this.state.dataSource}
         renderRow={this.renderRow}
         renderSectionHeader={this.renderSectionHeader}
       />
    

    5.2 代码

    /**
     * Sample React Native App
     * https://github.com/facebook/react-native
     * @flow
     */
    
    import React, {Component} from 'react';
    import {
      AppRegistry,
      StyleSheet,
      Text,
      View,
      ListView,
      Image,
      TouchableOpacity
    } from 'react-native';
    
    var carData = require("./Car.json");
    
    var rn0913ListViewTest03 = React.createClass({
      /**
       * 不可更改的属性
       * @returns {{}}
       */
      getDefaultProps() {
        return {};
      },
      /**
       * 状态机
       * @returns {{}}
       */
      getInitialState() {
    
        var getSectionHeaderData = (dataBlob, sectionID) => {
          return dataBlob[sectionID];
        }
        var getRowData = (dataBlob, sectionID, rowID) => {
          return dataBlob[sectionID + ":" + rowID];
        }
    
        return {
          // 这里就没有指定数据源,由于需要处理数据,所以在componentDidMount()方法中进行数据处理
          dataSource: new ListView.DataSource({
            getSectionHeaderData: getSectionHeaderData, // 获取组数据
            getRowData: getRowData, // 获取行数据
            rowHasChanged: (r1, r2) => {
              r1 !== r2
            }, // 什么时候创建行
            sectionHeaderHasChanged: (s1, s2) => {
              s1 !== s2
            } // 什么时候创建组
          })
        };
      },
      /**
       * 渲染界面
       */
      render() {
        return (
          <View style={styles.container}>
            <View style={styles.nav}>
              <Text style={styles.navTitle}>Chaos车库</Text>
            </View>
            <ListView
              dataSource={this.state.dataSource}
              renderRow={this.renderRow}
              renderSectionHeader={this.renderSectionHeader}
            />
          </View>
        );
      },
    
      /**
       * 渲染每一项
       * @param rowData
       * @returns {XML}
       */
      renderRow(rowData) {
        return (
          <TouchableOpacity activeOpacity={0.8}>
            <View style={styles.cellStyle}>
              <Image style={styles.imgStyle} source={{uri: rowData.icon}}/>
              <Text style={styles.carTitleStyle}>{rowData.name}</Text>
            </View>
          </TouchableOpacity>
        );
      },
      /**
       * 渲染每一组
       * @param sectionData
       * @returns {XML}
       */
      renderSectionHeader(sectionData) {
        return (
          <TouchableOpacity activeOpacity={0.8}>
            <View style={styles.headerStyle}>
              <Text style={styles.headerTextStyle}>{sectionData}</Text>
            </View>
          </TouchableOpacity>
        );
      },
    
      /**
       * 复杂操作
       */
      componentDidMount() {
        this.loadDataFromJson();
      },
      /**
       * 加载数据,处理数据
       */
      loadDataFromJson() {
        var jsonData = carData.data;
        var dataBlob = {}, // 对象
          sectionIDs = [],
          rowIDs = [], // 这是个二维数组
          cars = [];
    
        for (var i = 0; i < jsonData.length; i++) {
          // 确定每组的id
          sectionIDs.push(i);
          // 确定每组的id对应的组数据
          dataBlob[i] = jsonData[i].title;
          // 获取行集合
          cars = jsonData[i].cars;
          rowIDs[i] = []; // 二维数组,每一项都是行id的数组
          for (var j = 0; j < cars.length; j++) {
            rowIDs[i].push(j);
            // 确定每一行的数据
            dataBlob[i + ":" + j] = cars[j];
          }
        }
        // 给ListView的数据源赋值
        this.setState({
          dataSource: this.state.dataSource.cloneWithRowsAndSections(dataBlob, sectionIDs, rowIDs)
        });
      }
    });
    
    
    const styles = StyleSheet.create({
      container: {},
      nav: {
        height: 64,
        backgroundColor: '#eee',
        alignItems: 'center',
        justifyContent: 'center'
      },
      navTitle: {
        fontSize:26
      },
      headerStyle: {
        backgroundColor: '#ccc',
        height:30,
      },
      headerTextStyle: {
        lineHeight:30,
        paddingLeft:10
      },
      cellStyle: {
        borderBottomColor:'#eee',
        borderBottomWidth:0.5,
        flexDirection:'row',
        alignItems:'center',
        padding:10
      },
      imgStyle: {
         60,
        height: 60
      },
      carTitleStyle: {
        marginLeft:10
      }
    });
    
    AppRegistry.registerComponent('rn0913ListViewTest03', () => rn0913ListViewTest03);
    
    

    5.3 效果图

    感谢作者,原文地址,戳我

  • 相关阅读:
    Linux下redis的安装
    elasticsearch使用时问题
    Elasticsearch 2.x plugin 问题汇总
    elasticsearch-jdbc 插件说明
    ElasticSearch 2.x 问题汇总
    深入JVM《一》
    linux fastdfs 搭建配置(单机)
    mybatis自动generator
    spring-boot mybatis 配置 主从分离 事务
    Maven Nexus
  • 原文地址:https://www.cnblogs.com/gchlcc/p/7521265.html
Copyright © 2011-2022 走看看