react native之ListView和ListView.DataSource

ListView

ListView - 一个核心组件,用于高效地显示一个可以垂直滚动的变化的数据列表。最基本的使用方式就是创建一个ListView.DataSource数据源,然后给它传递一个普通的数据数组,再使用数据源来实例化一个ListView组件,并且定义它的renderRow回调函数,这个函数会接受数组中的每个数据作为参数,返回一个可渲染的组件(作为listview的每一行)。

ListView可以使用所有ScrollView的属性

属性:contentContainerStyleStyleSheetPropType(ViewStylePropTypes) //设置列表容器的属性

constructor(props) {
  super(props);
  var ds = new ListView.DataSource({rowHasChanged: (r1,r2) => r1 !== r2});
  this.state = {
    dataSource: ds.cloneWithRows(['row 1','row 2']),};
}
render() {
  return (
    <ListView
      contentContainerStyle={styles.contentContainer}   //设置列表容器的属性
      dataSource={this.state.dataSource}
      renderRow={(rowData) => <Text>{rowData}</Text>}
    />
  );
}

更多属性见官网.....

ListView.DataSource

ListViewDataSourceListView组件提供高性能的数据处理和访问。我们需要调用方法从原始输入数据中抽取数据来创建ListViewDataSource对象,并用其进行数据变更的比较。原始输入数据可以是简单的字符串数组,也可以是复杂嵌套的对象——分不同区(section)各自包含若干行(row)数据。

要更新datasource中的数据,请(每次都重新)调用cloneWithRows方法(如果用到了section,则对应cloneWithRowsAndSections方法)。数据源中的数据本身是不可修改的,所以请勿直接尝试修改。clone方法自动提取新数据并进行逐行对比(使用rowHasChanged方法中的策略),这样ListView就知道哪些行需要重新渲染了。

在下面这个例子中,一个组件在分块接受数据,这些数据由_onDataArrived方法处理——将新数据拼接(concat)到旧数据尾部,同时使用clone方法更新DataSource。我们使用concat方法修改this._data以创建新数组,注意不能使用push方法拼接数组。实现_rowHasChanged方法需要透彻了解行数据的结构,以便提供高效的比对策略。

constructor(props) {
  super(props);
  var ds = new ListView.DataSource({rowHasChanged: (r1,r2) => r1 !== r2});
  this.state = {
    ds,};
  this._data = []; 
}

_onDataArrived = (newData) => {
  this._data = this._data.concat(newData);
  this.setState({
    ds: this.state.ds.cloneWithRows(this._data)
  });
};

方法

constructor(params)

你可以在构造函数中针对section标题和行数据提供自定义提取方法hasChanged比对方法。如果不提供,则会使用认的defaultGetRowDatadefaultGetSectionHeaderData方法提取行数据和section标题

认的提取函数可以处理下列形式的数据:

{ sectionID_1: { rowID_1: rowData1,... },... }

或者:

{ sectionID_1: [ rowData1,rowData2,... ],... }

或者:

[ [ rowData1,... ]

构造函数可以接受下列四种参数(都是可选):

  • getRowData(dataBlob,sectionID,rowID);
  • getSectionHeaderData(dataBlob,sectionID);
  • rowHasChanged(prevRowData,nextRowData);
  • sectionHeaderHasChanged(prevSectionData,nextSectionData);

cloneWithRows(dataBlob,rowIdentities)

根据指定的dataBlobrowIdentitiesListViewDataSource复制填充数据。dataBlob即原始数据。需要在初始化时定义抽取函数(否则使用认的抽取函数)。

rowIdentities一个二维数组,包含了行数据对应的id标识符,例如[['a1','a2'],['b1','b2','b3'],...]。如果没有指定此数组,则认取行数据的key。

注:此方法实际并没有复制数据。它只是重新创建一个datasource,然后将你指定的dataBlob传递给构造函数中指定的提取函数,因而会抛弃先前的数据。如果你希望保留先前的数据,则必须先自行进行新老数据的合并处理,然后再将合并后的结果作为dataBlob传递给此方法调用

cloneWithRowsAndSections(dataBlob,sectionIdentities,rowIdentities)

方法作用基本等同cloneWithRows,区别在于可以额外指定sectionIdentities。如果你不需要section,则直接使用cloneWithRows即可。

sectionIdentities同理是包含了section标识符的数组。例如['s1','s2',...]。如果没有指定此数组,则认取section的key。

注:此方法会返回新的对象!

getRowCount()

getRowAndSectionCount()

rowShouldUpdate(sectionIndex,rowIndex)

返回值表明某行数据是否已变更,需要重新渲染。

getRowData(sectionIndex,rowIndex)

返回渲染行所需的数据(指定如何从原始dataBlob中提取数据)。

getRowIDForFlatIndex(index)

给定索引值,求其对应rowID。如果查找不到则返回null。

getSectionIDForFlatIndex(index)

给定索引值,求其对应sectionID。如果查找不到则返回null。

getSectionLengths()

返回一个数组,包含每个section的行数量

sectionHeaderShouldUpdate(sectionIndex)

返回值用于说明section标题是否需要重新渲染。

getSectionHeaderData(sectionIndex)

获取section标题数据。

仿IOS分组吸顶效果:

//模拟IOS的通讯录

import React,{ Component } from 'react';
import {
    AppRegistry,StyleSheet,Text,View,Image,ListView,TouchableOpacity
} from 'react-native';


//模拟数据
var ListData={
    data:[
        //组一
        {
            cars:[
                {
                    "icon":"QQ","name":"奥迪"
                },{
                    "icon":"QQ","name":"阿尔法"
                },"name":"阿斯顿马丁"
                },"name":"ALPIMA"
                },"name":"安凯客车"
                },"name":"ARCFOX"
                }

            ],title:"A"
        },//    组二
        {
            cars:[
                {
                    "icon":"QQ","name":"保时捷"
                },"name":"本田"
                },"name":"别克"
                },"name":"奔驰"
                },"name":"宝马"
                },"name":"宝骏"
                },"name":"比亚迪"
                },"name":"标志"
                },"name":"北京"
                },"name":"北汽幻速"
                },"name":"宝沃"
                },"name":"奔腾"
                },"name":"北汽绅宝"
                },"name":"宾利"
                },"name":"比速汽车"
                },"name":"北汽制造"
                },"name":"北汽威旺"
                },"name":"北汽新能源"
                },"name":"巴博斯"
                },"name":"布加迪"
                },"name":"北汽到达"
                }
            ],title:"B"
        },//   组三
        {
            cars:[
                {
                    "icon":"QQ","name":"长安"
                },"name":"长安酷尚"
                },"name":"长城"
                },"name":"长安轻型车"
                },"name":"昌河"
                },"name":"成功汽车"
                },"name":"长安跨越"
                }
            ],title:"C"
        }


    ]
}

var ListViewDemo3=React.createClass({
 getinitialState(){
     //获取组中的数据
    var getSectionData=(dataBlob,sectionID) => {
        return dataBlob[sectionID];
    }
     //获取行中的数据
     var getRowData=(dataBlob,rowID)=>{
        return dataBlob[sectionID+":"+rowID]
     };

    return{
        dataSource:new ListView.DataSource({
            getSectionData:getSectionData,//获取组中的数据
            getRowData:getRowData,//获取行中的数据
            rowHasChanged:(r1,r2) => r1 !== r2,sectionHeaderHasChanged:(s1,s2) => s1 !== s2,})
    }


 },//每一行中的数据
 renderRow(rowData){
     return(
         <TouchableOpacity activeOpacity={0.5}>
             <View style={styles.rowStyle}>
                 <Image style={styles.rowImg} source={{uri:rowData.icon}}/>
                 <Text>{rowData.name}</Text>
             </View>
         </TouchableOpacity>
     )
 },//每一组中的数据
 renderSectionHeader(sectionData,sectionID){
    return(
        <View style={styles.sectionHeader}>
            <Text style={{marginLeft:10,marginTop:5,color:"red"}}>{sectionData}</Text>
        </View>
    )

 },render(){
     return (
       <View style={styles.outerView}>
            {/*头部*/}
            <View style={styles.headerView}>
                <Text style={{color:"#fff",fontSize:25}}>see MyGo品牌</Text>
            </View>
           <ListView
               dataSource={this.state.dataSource}
               renderRow={this.renderRow}
               renderSectionHeader={this.renderSectionHeader}
           />
       </View>
     )
 },//复杂的操作:数据请求或者异步操作等等
 componentDidMount(){
     //调用JSON数据
     this.loadDataFromJson();
 },loadDataFromJson(){
     //拿到JSON数据
     var jsonData=ListData.data;
     //定义一些变量
     var dataBlob={},sectionIDs=[],rowIDs=[],cars=[];
     //遍历
     for(var i=0;i<jsonData.length;i++){
         //1、把组号放入sectionIDs数组中
         sectionIDs.push(i);
         //2、把组中的内容放入dataBlob对象中
         dataBlob[i]=jsonData[i].title;
         //3、取出该组中所有的车
         cars = jsonData[i].cars;
         rowIDs[i]=[];
         //4、遍历所有的车数组
         for(var g=0;g<cars.length;g++){
             //把行号放入rowID
             rowIDs[i].push(g);
             //把每一行的内容放入dataBlob对象中
             dataBlob[i+":"+g]=cars[g];
         }

     }
     //更新状态
     this.setState({
         dataSource:this.state.dataSource.cloneWithRowsAndSections(dataBlob,sectionIDs,rowIDs)
     })
 }


});

const styles = StyleSheet.create({
    outerView:{
        flex:1
    },headerView:{
        height:64,backgroundColor:"orange",justifyContent:"center",alignItems:"center"
    },rowStyle:{
        flexDirection:"row",alignItems:"center",padding:10,borderBottomColor:"#e8e8e8",borderBottomWidth:0.5
    },rowImg:{
        width:70,height:70,marginRight:10
    },sectionHeader:{
        backgroundColor:"#e8e8e8",height:30,justifyContent:"center"
    }

});

export default ListViewDemo3;

相关文章

react 中的高阶组件主要是对于 hooks 之前的类组件来说的,如...
我们上一节了解了组件的更新机制,但是只是停留在表层上,例...
我们上一节了解了 react 的虚拟 dom 的格式,如何把虚拟 dom...
react 本身提供了克隆组件的方法,但是平时开发中可能很少使...
mobx 是一个简单可扩展的状态管理库,中文官网链接。小编在接...
我们在平常的开发中不可避免的会有很多列表渲染逻辑,在 pc ...