ListView
在android中,如果我们需要显示一个ListView,有两项是比不可少的,首先是ListView的数据源,其次是ListView每个item的样式。ReactNative中一样。首先我们来看一个简单的例子:
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>}
/>
);
},
在render()中,我们渲染一个ListView,在ListView的属性中,我们指定了dataSource和renderRow,这两个属性分别代表ListView的数据源和渲染的每一行。
dataSource
如果我们要创建一个数据源,最基本的方法就是创建一个ListView.DataSource数据源,然后通过cloneWithRows方法为其传递一个数组。
其中提供给数据源的rowHasChanged函数可以告诉ListView它是否需要重绘一行数据,即数据是否发生了改变,即在需要重绘界面的时候会进行判断,如果之前页面中的改行数据没有发生变化,则不再进行重绘,否则进行重绘。
如上述代码,我们对数据源设置数据时直接传入一个数组,当然我们也可以通过一个获取数据的方法,在设置数据的时候调用方法即可:
constructor(props){
super(props);
var ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
this.state = {
dataSource: ds.cloneWithRows(this._genRows()),
};
}
_genRows(){
const dataBlob = [];
for(let i = 0 ; i< 200 ; i ++ ){
dataBlob.push("aa"+i);
}
return dataBlob;
}
这样通过方法获取数据,方便我们进行一些逻辑的处理。
renderRow
(rowData, sectionID, rowID, highlightRow) => renderable
该属性需要传入一个方法,该方法如上所示,他会从数据源中接受一条数据,以及他和他所在的section的Id,返回一个可渲染的组件来为这行数据进行渲染,默认情况下参数中的数据就是放进数据源中的数据本身,不过也可以提供一些转换器。
如果某一行正在被高亮(通过调用highlightRow函数),ListView会得到相应的通知。当一行被高亮时,其两侧的分割线会被隐藏。行的高亮状态可以通过调用highlightRow(null)来重置。
_renderRow(rowData, sectionID, rowID){
return (
<View>
<Text>{"rowData:"+rowData+" rowId:"+rowID}</Text>
</View>
);
}
render() {
return (
<ListView
dataSource={this.state.dataSource}
renderRow={this._renderRow}
/>
);
},
因为renderRow中的方法会自动接受从数据源中的一条数据,因此我们可以通过调用外部方法的方式进行实现,同时只需要在外部方法的参数中传入我们需要从数据源中获取的数据即可,如上代码所示。
当我们需要实现比较复杂的布局时,也可以通过导入外部组件的方式作为ListView的每一行的样式。
例如我们自定义了一个组件Item_MyListView,我们需要在文件开头通过import方式将其导入到当前组件中:
import Item_MyListView from './Item_MyListView';
然后就可以通过导入的名称直接使用我们导入的组件了:
_renderRow(rowData, sectionID, rowID){
return (
<TouchableOpacity onPress={this._pressRow}>
<View>
<Text>{"rowData:"+rowData+" rowId:"+rowID}</Text>
<Item_MyListView></Item_MyListView>
</View>
</TouchableOpacity>
);
}
ListView的点击
当我们需要给ListView的每一行添加点击事件时,只需要在其外层包裹一层TouchableOpacity或者TouchableHighlight,定义好onPress方法即可。
如下代码所示:
_pressRow(rowID){
alert("hellow"+rowID);
}
_renderRow(rowData, sectionID, rowID){
return (
<TouchableOpacity onPress={()=>this._pressRow(rowID)}>
<View>
<Text>{"rowData:"+rowData+" rowId:"+rowID}</Text>
<Item_MyListView info={rowData}></Item_MyListView>
</View>
</TouchableOpacity>
);
}
需要注意的是,在ListView的renderRow属性中调用_renderRow一定要绑定this,否则onPress中的this就会指向错误,如下所示:
<ListView dataSource={this.state.dataSource} renderRow={this._renderRow.bind(this)}/>
完整代码如下所示:
import React,{
View,
Text,
TouchableOpacity,
ListView,
} from 'react-native';
import Item_MyListView from './Item_MyListView';
export default class SecondPageComponent extends React.Component{
constructor(props){
super(props);
var ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
this.state = {
dataSource: ds.cloneWithRows(this._genRows()),
};
}
_genRows(){
const dataBlob = [];
for(let i = 0 ; i< 200 ; i ++ ){
dataBlob.push("aa"+i);
}
return dataBlob;
}
_pressRow(rowID){
alert("hellow"+rowID);
}
_renderRow(rowData, sectionID, rowID){
return (
<TouchableOpacity onPress={()=>this._pressRow(rowID)}>
<View>
<Text>{"rowData:"+rowData+" rowId:"+rowID}</Text>
<Item_MyListView info={rowData}></Item_MyListView>
</View>
</TouchableOpacity>
);
}
render(){
return (
<View style={{flex:1,}}>
<ListView dataSource={this.state.dataSource} renderRow={this._renderRow.bind(this)}/>
</View>
);
}
}
其中Item_MyListView只是随意定义了一个组件,没什么实际意义,就不再展示。
最终效果如下图所示: