React-Native Listview组件用法详解

ListView作为React Native的核心组件,用于高效地显示一个可以垂直滚动的变化的数据列表。其中最重要的属性之一是DataSource,列表依赖的数据源,用于实例化一个ListView对象。此外ListView可以使用所有ScrollView的属性。一个最简单的例子:

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
      dataSource={this.state.dataSource}
      renderRow={(rowData) => <Text>{rowData}</Text>}
    />
  );
}

然而实际开发中往往遇到更复杂的需求,本文将介绍如何使用ListView一些高级特性解决难题。

需求描述:实现一个分组商品列表,最终陈列效果为多行多列。具体如图标红区域。

需求拆分:ListView Section,每一块(Section)包含标题+内容。渲染块标题的函数为renderSectionHeader;渲染条目数据的函数为renderRow。难点在于每一行显示两条数据,ListView contentContainerStyle属性赋值为如下对象,出现只能显示一行的bug,不分组的ListView不会出现这个问题。

{
        flexDirection: 'row',
        flexWrap: 'wrap'
 }

最终解决方案:在ListView 和单条目数据Row之间,插入一个组件,该组件数据源为行数据(长度为2或者1的数组),以此实现多行多列。也就是说renderRow函数从渲染单条目数据,转为渲染一行所需的数据。

import React ,{ Component } from 'react';
import {
    View,
    ListView,
    Text,
    Image,
    TouchableHighlight,
    StyleSheet,
    Dimensions,
} from 'react-native';
const windowWidth = Dimensions.get('window').width;
var { ListJSON } = require('../JSON/ListJSON'),Utils = require('./Utils');
class ProductInfo extends Component{
    constructor(props){
        super(props);
    }
    _gotoBuy(){

    }
    render(){
        var product = this.props.product;
        return (
                <TouchableHighlight onPress={this._gotoBuy} underlayColor={'rgba(0, 0, 0, 0.3)'} style={styles.productWrapper}>
                    <View style={styles.productDetail}>
                        <Text style={styles.productDetailTxt}>{product.flowTotalUnit}</Text>
                        <Text style={styles.productDetailTxt}>/{product.retailPrice / 100}元</Text>
                        <Text style={styles.productDetailTxt}>{!!product.expiredPrice ? (product.expiredPrice / 100) + '元' : ''}</Text>
                    </View>
                </TouchableHighlight>  
        );
    }
}
class ProductRow extends Component{
    constructor(props){
        super(props);
    }
    render(){
        return (
            <View style={styles.productFlex}>
            {
                this.props.products.map((item,i) => <ProductInfo product={ item } key = { i }></ProductInfo>)
            }     
            </View>
        )
    }
}
class List extends Component{ 
    constructor(props){
        super(props);
        var _getSectionData = (dataBlob, sectionID) => {
            return dataBlob[sectionID];
        }
        var _getRowData = (dataBlob, sectionID, rowID) => {
            return dataBlob[sectionID + ':' + rowID];
        }
        var data = Utils.translateData(ListJSON);
        const ds = new ListView.DataSource({
            getSectionData: _getSectionData,
            getRowData: _getRowData,
            rowHasChanged: (row1, row2) => row1 !== row2,
            sectionHeaderHasChanged: (s1, s2) => s1 !== s2
        });
        this.state = {
            dataSource: ds.cloneWithRowsAndSections(data.dataBlob, data.sectionIDs, data.rowIDs),
        }
    }
    renderRow(rowData, sectionID, rowID) {
        //console.log(rowData,'****')
        return (
            <ProductRow products={rowData}></ProductRow>
        );
    }
    renderSectionHeader(sectionData, sectionID){
        return (
            <View>
                <Text style={styles.sectionTtl}>{sectionData.scope}{sectionData.type}<Text> | {sectionData.tip}</Text></Text>
            </View>
        );
    }
    render(){
        return (
            <View style={styles.container} >
                <ListView dataSource={this.state.dataSource}
                contentContainerStyle={styles.listview}
                    renderRow  = {this.renderRow}
                    renderSectionHeader = {this.renderSectionHeader}
                />
            </View>
        );
    }
}
const styles = StyleSheet.create({
    container:{
        padding:10,
    },
    listview: {
        width:windowWidth-20
    },
    sectionTtl:{
        height:30,
        textAlignVertical:'center'
    },
    productFlex:{
        paddingBottom:10,
        flexDirection:'row',
        justifyContent:'space-between'
    },
    productWrapper:{
        width:(windowWidth-20)*0.485,
        borderWidth:1,
        borderColor:'#e2e2e2',
        borderRadius:4
    },
    productDetail:{
        flexDirection: 'row',
        justifyContent:'center'
    },
    productDetailTxt:{
        height:56,
        textAlignVertical:'center',
    }
});
module.exports = {
    List:List
}

 分组列表需要的数据格式如下:

{
            dataBlob: dataBlob,
            sectionIDs: sectionIDs,
            rowIDs: rowIDs
}

处理section数据方法如下

dataBlob['s'+sectionIdx] = {
   "scope": scopev.scopeName,
   "type": typeV.typeName,
   "tip": tip
}
sectionIDs.push('s'+sectionIdx);
rowIDs[sectionIdx] = [];
var rowIdx = 0;
_.forEach(list, function (item,index) {
    let rowAttr = 's'+sectionIdx+':'+rowIdx;
    if(index%2==0){
       dataBlob[rowAttr] = [];
       rowIDs[sectionIdx].push(rowIdx); 
   }else{
       rowIdx++;
   }
   dataBlob[rowAttr].push(item); 
});
sectionIdx++;

  

 

  

posted on 2016-08-30 15:05  NicoleBJ  阅读(3592)  评论(1编辑  收藏  举报

导航