CRNListView
一个核心组件,用于高效地显示一个可以垂直滚动的变化的数据列表。最基本的使用方式就是创建一个CRNListView.DataSource
数据源,然后给它传递一个普通的数据数组,再使用数据源来实例化一个ListView
组件,并且定义它的renderRow
回调函数,这个函数会接受数组中的每个数据作为参数,返回一个可渲染的组件(作为listview的每一行)。
该ListView是在Native的UITableView基础上封装的列表视图组件,与Facebook官方的ListView相比,支持cell的重用,优化了性能,并且集成了下拉刷新、点击加载更多、右侧索引栏等功能,但使用该ListView必须事先知道每个要渲染的row或sectionHeader的高度。
最简单的例子:
constructor(props) {
super(props);
var ds = new CRNListView.DataSource({});
this.state = {
dataSource: ds.cloneWithRows(['row 1', 'row 2']),
};
}
render() {
return (
<
CRNListView
dataSource={this.state.dataSource}
renderRow={(rowData) =
>
<
Text
>
{rowData}
<
/Text
>
}
/
>
);
}
属性
dataSource CRNListViewDataSource
CRNListView.DataSource实例(列表依赖的数据源)
renderHeader function
() => renderable
渲染整个ListView的头部,页头会在每次渲染过程中都重新渲染(如果提供了这些属性)。如果它们重绘的性能开销很大,把他们包装到一个StaticContainer或者其它恰当的结构中。
renderRow function
(rowData, sectionID, rowID) => renderable
从数据源(Data source)中接受一条数据,以及它和它所在section的ID。返回一个可渲染的组件来为这行数据进行渲染。默认情况下参数中的数据就是放进数据源中的数据本身,不过也可以提供一些转换器。
rowHeight number
如果每个row都是相同的高度,可以在此统一设置,设置了rowHeight后,对rowHeights的设置无效
rowHeights array or json
如果各个row的高度不同,需在此设置,数据结构和dataSource的数据结构一致:
sectionID_1: { rowID_1: height1, ... }, ... }
或者:
{ sectionID_1: [ height1, height2, ... ], ... }
或者:
[ [ height1, height2, ... ], ... ]
renderSectionHeader function
(sectionData, sectionID) => renderable
如果提供了此函数,会为每个小节(section)渲染一个粘性的标题。
粘性是指当它刚出现时,会处在对应小节的内容顶部;继续下滑当它到达屏幕顶端的时候,它会停留在屏幕顶端,一直到对应的位置被下一个小节的标题占据为止。
sectionHeaderHeight number
如果每个sectionHeader都是相同的高度,可以在此统一设置,设置了sectionHeader后,对sectionHeaders的设置无效
sectionHeaderHeights array or json
如果各个sectionHeader的高度不同,需在此设置,数据结构和dataSource的sectionData的数据结构一致:
{ sectionID_1: height1, sectionID_2: height2, ... }
或者:
[ height1, height2, ... ]
onSelect function
(rowData,sectionID,rowID) => void
用户点击某个row的时候触发的回调,传递进来的参数是点击的rowData和对应的sectionID,rowID
enablePullDownToRefresh boolean
是否开启下拉刷新,默认否
onPullDownToRefresh function
触发下拉刷新后的回调,刷新数据完成后需要设置isFinishRefresh为true
enableLoadMore boolean
是否开启点击加载更多,默认否
onLoadMore function
点击加载更多后的回调,刷新数据完成后需要设置loadMoreState的状态
loadMoreState enum('normal', 'loading', 'done')
点击加载更多的状态,接收到onLoadMore的回调是设置为loading
,加载数据完成后如果还有数据可加载则设置为normal
,如果没有数据可加载了则设置为done
sectionIndexTitles array
ListView右侧的索引数组的标题。(暂时只有ios支持)
mappingForSectionIndexTitles object
ListView右侧的索引数组标题与索引section的对应关系,默认是sectionIndexTitles的每个title对应该title的下标。(暂时只有ios支持)
方法
finishRefresh()
下拉刷新数据完成后需要调用此方法
scrollTo(x: number, y: number, animated: boolean)
滚动到指定的x, y偏移处。第三个参数为是否启用平滑滚动动画。
使用示例:
scrollTo({x: 0, y: 200, animated: true})
例子
'use strict';
import {
AppRegistry,
View,
Dimensions,
TouchableOpacity,
Text,
Image,
} from 'react-native';
import React, {Component} from 'react';
import { CRNListView } from "@ctrip/crn";
let ds = new CRNListView.DataSource({})
class RNDemo extends Component {
constructor(props){
super(props);
var data=[];
for (var i = 0; i
<
3; i++) {
var items = [];
for (var j = 0; j
<
20; ++j) {
items.push('item--origin--'+j);
}
data.push(items)
}
var dataSource= ds.cloneWithRowsAndSections(data)
this.state={
dataSource:dataSource,
isFinishRefresh:false,
loadMoreState:'normal',
}
}
render(){
var rowHeights=[];
for (var i = 0; i
<
3; i++) {
var items = [];
for (var j = 0; j
<
20; ++j) {
items.push(j*20);
}
rowHeights.push(items)
}
var sectionHeaderHeights = [];
for (var j = 0; j
<
3; ++j) {
sectionHeaderHeights.push(j*20);
}
return (
<
CRNListView style={{flex:1}}
ref={listView =
>
this.listView = listView}
rowHeight={50}
renderRow={this.renderRow}
sectionHeaderHeight={60}
renderSectionHeader={this.renderSectionHeader}
renderHeader={this.renderHeader}
onPress={this.onPress.bind(this)}
enablePullDownToRefresh={true}
onPullDownToRefresh={this.onPullDownToRefresh.bind(this)}
enableLoadMore={true}
onLoadMore={this.onLoadMore.bind(this)}
dataSource={this.state.dataSource}
loadMoreState={this.state.loadMoreState}
rowHeights={rowHeights}
sectionHeaderHeights={sectionHeaderHeights}
>
<
/CRNListView
>
);
}
renderRow(rowData, sectionID, rowID) {
return (
<
View
>
<
Image style={{width:30,height:30}} source={{uri: 'https://ss3.bdstatic.com/iPoZeXSm1A5BphGlnYG/icon/95487.png'}}/
>
<
Text
>
section:{sectionID},row:{rowID},data:{rowData}
<
/Text
>
<
/View
>
);
}
renderSectionHeader(sectionData, sectionID){
return (
<
View style={{backgroundColor:"#cccccc",flex:1}}
>
<
Text style={{marginTop:20}}
>
'*********section:{sectionID}*********'
<
/Text
>
<
/View
>
);
}
renderHeader(){
return (
<
View style={{backgroundColor:"#097f34",flex:1}}
>
<
Text style={{marginTop:20}}
>
'++++++++++tableHeader++++++++++'
<
/Text
>
<
/View
>
);
}
onPress(rowData,sectionID,rowID){
alert(JSON.stringify(rowData)+'---'+JSON.stringify(sectionID)+'---'+JSON.stringify(rowID))
}
onPullDownToRefresh(){
var self=this
setTimeout(function(){
var data=[];
for (var i = 0; i
<
3; i++) {
var items = [];
for (var j = 0; j
<
20; ++j) {
items.push('item--refresh--'+j);
}
data.push(items)
}
var dataSource = ds.cloneWithRowsAndSections(data);
self.setState({dataSource:dataSource})
self.listView.finishRefresh();
},2000)
}
onLoadMore(){
var self=this
self.setState({loadMoreState:'loading'})
setTimeout(function(){
var data=[];
for (var i = 0; i
<
3; i++) {
var items = [];
for (var j = 0; j
<
20; ++j) {
items.push('item--loadmore--'+j);
}
data.push(items)
}
var dataSource= ds.cloneWithRowsAndSections(data);
self.setState({dataSource:dataSource, loadMoreState:'normal'})
},2000)
}
}
AppRegistry.registerComponent('RNDemo', () =
>
RNDemo);