React Native基礎:15-ListView組件
ListView組件簡介
ListView組件是一個可以在垂直方向滾動的列表組件。從本質來說,ListView組件是對ScrollView組件的定制,優化了組件對內存資源的使用效率,提高了性能。與ScrollView組件不同的是,ListView組件不會把所有元素都立刻渲染出來,其只會渲染屏幕內可見區域的元素,從而節省對硬件資源的消耗。
一般來說,如果需要展示的數據量很大,并且每一行界面元素的結構相同或相似,推薦使用ListView組件來渲染界面。由于手機屏幕的尺寸都不大,因此使用React Native開發的移動應用,基本上都會用到ListView組件。
ListView組件有兩個核心屬性:dataSource與renderRow,這兩個屬性必需設置。ListView組件通過dataSource屬性獲取需要顯示的數據,并且通過renderRow獲取數據展示的樣式。
render() {
return (
<ListView
dataSource={this.state.dataSource}
renderRow={(rowData) => <Text>{rowData}</Text>}
/>
);
}
ListViewDataSource介紹
ListViewDataSource類型的屬性dataSource為ListView組件提供高性能的數據處理和訪問。我們需要調用方法從原始輸入數據中抽取數據來創建ListViewDataSource對象,并用其進行數據變更的比較。原始輸入數據可以是簡單的字符串數組,也可以是復雜嵌套的對象——分不同區(section)各自包含若干行(row)數據。
每次更新datasource中的數據,都需要重新調用cloneWithRows方法(如果用到了section,則對應cloneWithRowsAndSections方法)。數據源中的數據本身是不可修改的,所以請勿直接嘗試修改。clone方法會自動提取新數據并進行逐行對比(使用rowHasChanged方法中的策略),這樣ListView就知道哪些行需要重新渲染了。
在下方的示例代碼中,先通過創建設置rowHasChanged屬性來創建一個ListView.DataSource實例。rowHasChanged是ListView.DataSource必需的屬性,通過這個屬性可以獲取哪些行的數據發生了變化,進而可以獲取到ListView中的哪些行需要重新渲染。ListView.DataSource的實例ds創建完成后,通過cloneWithRows方法來進行設置數據。cloneWithRows方法會自動提取新數據,并對比數據源檢查數據的變化,進而去刷新對應的行。如果dataSource中的數據發生了變化,需要重新調用cloneWithRows方法來設置它的數據。
var ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
var dataSource = ds.cloneWithRows(this._genRows({}));
在ListViewDataSource中,提供了一些用于對ListViewDataSource進行構建以及操作的方法,如下幾個比較常用。
constructor(params) :可以在此構造函數中針對section標題以及行數據提供自定義的提取方法和hasChanged比對方法。如果不提供,則會使用默認的defaultGetRowData和defaultGetSectionHeaderData方法來提取行數據和section標題。
cloneWithRows(dataBlob, rowIdentities) :根據指定的dataBlob和rowIdentities為ListViewDataSource復制填充數據。dataBlob即原始數據。需要在初始化時定義抽取函數,否則使用默認的抽取函數。rowIdentities是一個二維數組,包含了行數據對應的id標識符,例如[['a1', 'a2'], ['b1', 'b2', 'b3'], ...]。如果沒有指定此數組,則默認取行數據的key。
cloneWithRowsAndSections(dataBlob, sectionIdentities, rowIdentities) :此方法作用基本等同cloneWithRows,區別在于可以額外指定sectionIdentities 。sectionIdentities是包含了section標識符的數組,例如['s1', 's2', ...]。如果沒有指定此數組,則默認取section的key。
getRowData(sectionIndex, rowIndex) :返回渲染行所需的數據。
getSectionHeaderData(sectionIndex) :獲取section標題數據。
示例代碼
接下來我們實現一個ListView組件的例子,在ListView中會顯示100行數據,當用戶點擊某一行后會在標題上添加"(pressed)"提示。
- 在終端中執行如下命令,創建ListViewDemo工程;
react-native init ListViewDemo
- 使用Atom打開工程的index.ios.js文件,編寫組件所使用的樣式
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
backgroundColor: '#F5FCFF',
paddingTop: 20,
},
row: {
flex: 1,
margin: 10,
},
});
- 創建ListView組件,設置其dataSouce和renderRow屬性,并實現用戶點擊每一行后更新顯示內容的功能。
export default class ListViewDemo extends Component {
_pressData = ({}: {[key: number]: boolean})
constructor(props) {
super(props);
this._renderRow = this._renderRow.bind(this);
this._pressRow = this._pressRow.bind(this);
var ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
this.state = {
dataSource: ds.cloneWithRows(this._genRows({})),
};
}
render() {
return (
<View style={styles.container}>
<ListView
dataSource={this.state.dataSource}
renderRow={this._renderRow}
renderSeparator={this._renderSeparator}
/>
</View>
);
}
_renderRow(rowData: string, sectionID: number, rowID: number, highlightRow: (sectionID: number, rowID: number) => void) {
return (
<TouchableHighlight onPress={() => {
console.log("this");
console.log(this);
this._pressRow(rowID);
highlightRow(sectionID, rowID);
}}>
<View style={styles.row}>
<Text>
{rowData}
</Text>
</View>
</TouchableHighlight>
);
}
_pressRow(rowID: number) {
this._pressData[rowID] = !this._pressData[rowID];
this.setState({dataSource: this.state.dataSource.cloneWithRows(
this._genRows(this._pressData)
)});
}
_genRows(pressData: {[key: number]: boolean}): Array<string> {
var dataBlob = [];
for (var ii = 0; ii < 100; ii++) {
var pressedText = pressData[ii] ? ' (pressed)' : '';
dataBlob.push('Row ' + ii + pressedText);
}
return dataBlob;
}
}
- 使用import加載項目所使用的模塊,并且注冊組件ListViewDemo成為整個應用的根容器。
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
ListView,
TouchableHighlight,
} from 'react-native';
AppRegistry.registerComponent('ListViewDemo', () => ListViewDemo);
- 在終端中執行下面的命令運行程序,在iOS模擬器中可以看到展示的ListView組件,當我們點擊某一行時,改行的文字會發生改變。
react-native run-ios