React Native填坑之旅--ListView篇
列表显示数据,基本什么应用都是必须。笔者写作的时候RN版本是0.34。今天就来从浅到深的看看React Native的ListView怎么使用。 首先是使用写死的数据,之后会使用网络请求的数据在界面中显示。最后加上一个ActivityIndicator,网络请求的过程中显示Loading图标,加载完成之后显示数据,隐藏Loading图标。 最简单的//@flow import React from 'react'; import { Text,View,ListView } from 'react-native'; export default class DemoList extends React.Component { constructor(props) { super(props); const 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>} /> ); } } 引入所需要的内置组件之类的就不多说了。 第一步,在 之后,在state里面设置数据源。下面从网络请求数据的时候state的作用就更加明显了。RN的组件在state发生改变的时候就会重绘。这个下面会详细解释。 最后,在 一步一步接近实际产品开发下面就把绘制行的部分抽象出来。在Native应用的开发中,无论是iOS还是Android,行绘制的部分都是单独出来的。在RN里虽然可以不独立出来,但是你也看到了,这样的写法遇到稍微复杂一点的行内容的时候就捉襟见肘了。不独立出来行绘制部分代码会很难维护。 这部分不复杂,独立出来以后是这样的: import //...略... export default class DemoList extends React.Component { constructor(props) { super(props); const ds = new ListView.DataSource({rowHasChanged: (r1,'row 2']) }; //bind this._renderRow = this._renderRow.bind(this); } _renderRow(rowData) { return ( <View style={{height: 50}}> <Text>{rowData}</Text> </View> ); } render() { return ( <ListView dataSource={this.state.dataSource} renderRow={this._renderRow} /> ); } } 这个例子和上例基本上一样。只是多了一个 注意:在使用这个方法以前,一定要绑定: 在绘制行的时候,比之前稍微有一点改动。行文本的外面套了一个View,并指定这个View的高度为50。 加上装饰从现在来看,数据只有两行。如果不滑动一下的话,看起来和两个上下排列的Text没有什么区别。 首先我们加一个分割线: export default class DemoList extends React.Component { constructor() { //记得使用方法之前绑定 this._renderSeparator = this._renderSeparator.bind(this); } _renderRow(rowData) { // ...略... } _renderSeparator(sectionID: number,rowID: number,adjacentRowHighlighted: bool) { return ( <View key={`{sectionID}-${rowID}`} style={{height: 1,backgroundColor: 'black'}}> </View> ); } render() { return ( <ListView dataSource={this.state.dataSource} renderRow={this._renderRow} renderSeparator={this._renderSeparator} /> ); } } 这里需要额外说明一些,在方法里 如果你从一开始就没打算跟flow扯上任何关系,那么就按照ES标准写就好。 至于分割线也是非常简单。我们这就返回了一个高度一个像素的,背景色为黑色的view。 点击和高亮Row的点击不想Native那样,默认的一般就有了。在RN里,我们需要手动赋予一行可以被点击的功能。 _renderRow(rowData: string,sectionID: number,highlightRow: (sectionID: number,rowID: number) => void) { return ( <TouchableHighlight onPress={() => { this._pressRow(rowID); highlightRow(sectionID,rowID); }}> <View style={styles.row}> <Text style={styles.text}>{rowData}</Text> </View> </TouchableHighlight> ); } 在RN里处理一般点击的不二选择就是 当然,这里就少不了用到样式了: const styles = StyleSheet.create({ row: { flexDirection: 'row',justifyContent: 'center',padding: 10,backgroundColor: '#F6F6F6',},text: { flex: 1,seperator: { height: 1,backgroundColor: '#CCCCCC' } }); 把Cell分离在实际的开发中,一般没有人会把Row(或者行)的绘制和 首先创建一个单独的文件,定义Cell: import React from 'react'; import { View,Text,TouchableHighlight,StyleSheet } from 'react-native'; export default class DemoCell extends React.Component { render() { return ( <View> <TouchableHighlight onPress={this.props.onSelect}> <View style={styles.row}> <Text style={styles.text}>{this.props.rowData}</Text> </View> </TouchableHighlight> </View> ); } }; const styles = StyleSheet.create({ row: { flexDirection: 'row',}); Row也是一个组件,是一个组件就可以在另外的组建里渲染。所以,单独定义的Row就是这么用的。 回到demoList.js文件。在 _renderRow(rowData: string,rowID: number) => void) { return ( // <TouchableHighlight onPress={() => { // this._pressRow(rowID); // highlightRow(sectionID,rowID); // }}> // <View style={styles.row}> // <Text style={styles.text}>{rowData}</Text> // </View> // </TouchableHighlight> <DemoCell onSelect={() => { this._pressRow(rowID); highlightRow(sectionID,rowID); }} rowData={rowData}/> ); } 结合网络请求ListView在实战中,除非是Settings之类的界面,数据都是从网络请求得到的。上一节中正好已经讲述了如何使用RN内置的fetch请求网络数据。这一节中就是用fetch来请求dribbble的数据。 在使用dribbble的数据之前你需要注册,获得Access Token。这是请求认证所必须的。 export default class DemoList extends React.Component { constructor(props) { super(props); const ds = new ListView.DataSource({rowHasChanged: (r1,r2) => r1 !== r2}); this.state = { isLoading: false,isLoadingTail: false,dataSource: new ListView.DataSource({ rowHasChanged: (row1,row2) => row1 !== row2,}),filter: this.props.filter,queryNumber: 0,}; //...略... } //...略... _getShots(query: string) { this.setState({ isLoading: true,queryNumber: this.state.queryNumber + 1,}); api.getShotsByType(query,1).then((responseData) => { this.setState({ isLoading: false,dataSource: this._getDataSource(responseData),}); }).catch((error) => { this.LOADING[query] = false; this.resultsCache.dataForQuery[query] = undefined; this.setState({ dataSource: this._getDataSource([]),isLoading: false,}); }); } 还是在类 state的改变会影响到组件的绘制。所以,在 在 那么loading界面是什么样呢? <View style={{alignItems: 'center',flex: 1,backgroundColor: 'white'}}> <ActivityIndicator animating={true} style={[styles.centering]} size="large" color="#cccccc" /> </View> 组合起来在类 _renderView() { if (this.state.isLoading) { return ( <UNActivityIndicator loadingType={LOADING_TYPE.Large} /> ); } return ( <View style={styles.container}> <ListView dataSource={this.state.dataSource} renderRow={this._renderRow} renderSeparator={this._renderSeparator} automaticallyAdjustContentInsets={false} /> </View> ); } 在renderView的时候,先检查 填坑完毕以上就是处理ListView和其中的Cell的一些常见问题的方法。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |