技术控

    今日:126| 主题:49390
收藏本版 (1)
最新软件应用技术尽在掌握

[其他] React Native填坑之旅--ListView篇

[复制链接]
你会发光但我怕烫 发表于 2016-10-6 08:28:12
244 5

立即注册CoLaBug.com会员,免费获得投稿人的专业资料,享用更多功能,玩转个人品牌!

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
列表显示数据,基本什么应用都是必须。笔者写作的时候RN版本是0.34。今天就来从浅到深的看看React Native的ListView怎么使用。
  首先是使用写死的数据,之后会使用网络请求的数据在界面中显示。最后加上一个ActivityIndicator,网络请求的过程中显示Loading图标,加载完成之后显示数据,隐藏Loading图标。
  最简单的

  1. [email protected]
  2. import React from 'react';
  3. import {
  4.   Text,
  5.   View,
  6.   ListView
  7. } from 'react-native';
  8. export default class DemoList extends React.Component {
  9.   constructor(props) {
  10.     super(props);
  11.     const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
  12.     this.state = {
  13.       dataSource: ds.cloneWithRows(['row 1', 'row 2'])
  14.     };
  15.   }
  16.   render() {
  17.     return (
  18.       <ListView
  19.         dataSource={this.state.dataSource}
  20.         renderRow={(rowData) => <Text>{rowData}</Text>} />
  21.     );
  22.   }
  23. }
复制代码
引入所需要的内置组件之类的就不多说了。
  第一步,在    constructor里设置数据源,并同时指定什么时候重新绘制一行,就是在这个时候    (r1, r2) => r1 !== r2}重绘。  
  之后,在state里面设置数据源。下面从网络请求数据的时候state的作用就更加明显了。RN的组件在state发生改变的时候就会重绘。这个下面会详细解释。
  最后,在    render方法里返回ListView,这里的props里有一个    renderRow。在这里指定的代码就是把数据源中每一行的数据绘制在    Text里。  
  一步一步接近实际产品开发

  下面就把绘制行的部分抽象出来。在Native应用的开发中,无论是iOS还是Android,行绘制的部分都是单独出来的。在RN里虽然可以不独立出来,但是你也看到了,这样的写法遇到稍微复杂一点的行内容的时候就捉襟见肘了。不独立出来行绘制部分代码会很难维护。
  这部分不复杂,独立出来以后是这样的:
  1. import //...略...
  2. export default class DemoList extends React.Component {
  3.   constructor(props) {
  4.     super(props);
  5.     const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
  6.     this.state = {
  7.       dataSource: ds.cloneWithRows(['row 1', 'row 2'])
  8.     };
  9.     //bind
  10.     this._renderRow = this._renderRow.bind(this);
  11.   }
  12.   _renderRow(rowData) {
  13.     return (
  14.       <View style={{height: 50}}>
  15.         <Text>{rowData}</Text>
  16.       </View>
  17.     );
  18.   }
  19.   render() {
  20.     return (
  21.       <ListView dataSource={this.state.dataSource}
  22.         renderRow={this._renderRow} />
  23.     );
  24.   }
  25. }
复制代码
这个例子和上例基本上一样。只是多了一个    _renderRow(rowData)方法。  
  注意:在使用这个方法以前,一定要绑定:    this._renderRow = this._renderRow.bind(this);。绑定也可以这样    <ListView dataSource={this.state.dataSource} renderRow={this._renderRow.bind(this)} />。  
  在绘制行的时候,比之前稍微有一点改动。行文本的外面套了一个View,并指定这个View的高度为50。
  加上装饰

  从现在来看,数据只有两行。如果不滑动一下的话,看起来和两个上下排列的Text没有什么区别。
  首先我们加一个分割线:
  1. export default class DemoList extends React.Component {
  2.   constructor() {
  3.     //记得使用方法之前绑定
  4.     this._renderSeparator = this._renderSeparator.bind(this);
  5.   }
  6.   _renderRow(rowData) {
  7.     // ...略...
  8.   }
  9.   _renderSeparator(sectionID: number, rowID: number, adjacentRowHighlighted: bool) {
  10.     return (
  11.       <View key={`{sectionID}-${rowID}`}
  12.         style={{height: 1, backgroundColor: 'black'}}>
  13.       </View>
  14.     );
  15.   }
  16.   render() {
  17.     return (
  18.       <ListView dataSource={this.state.dataSource}
  19.         renderRow={this._renderRow}
  20.         renderSeparator={this._renderSeparator}
  21.         />
  22.     );
  23.   }
  24. }
复制代码
这里需要额外说明一些,在方法里    _renderSeparator(sectionID: number, rowID: number, adjacentRowHighlighted: bool)我看看到了在参数的名称后面都有类型的说明。这个不是ES6的也不是js里的,而是FB自己搞的一套静态类型检查工具里的定义。这个工具叫    Flow。  
  如果你从一开始就没打算跟flow扯上任何关系,那么就按照ES标准写就好。
  至于分割线也是非常简单。我们这就返回了一个高度一个像素的,背景色为黑色的view。
  点击和高亮

  Row的点击不想Native那样,默认的一般就有了。在RN里,我们需要手动赋予一行可以被点击的功能。
  1. _renderRow(rowData: string, sectionID: number, rowID: number, highlightRow: (sectionID: number, rowID: number) => void) {
  2.     return (
  3.       <TouchableHighlight onPress={() => {
  4.         this._pressRow(rowID);
  5.         highlightRow(sectionID, rowID);
  6.       }}>
  7.         <View style={styles.row}>
  8.           <Text style={styles.text}>{rowData}</Text>
  9.         </View>
  10.       </TouchableHighlight>
  11.     );
  12.   }
复制代码
在RN里处理一般点击的不二选择就是    TouchableHighlight。在    TouchableHighlight里的    onPress里调用自定义的_pressRow方法处理点击,    highlightRow方法高亮行。  
  当然,这里就少不了用到样式了:
  1. const styles = StyleSheet.create({
  2.   row: {
  3.     flexDirection: 'row',
  4.     justifyContent: 'center',
  5.     padding: 10,
  6.     backgroundColor: '#F6F6F6',
  7.   },
  8.   text: {
  9.     flex: 1,
  10.   },
  11.   seperator: {
  12.     height: 1,
  13.     backgroundColor: '#CCCCCC'
  14.   }
  15. });
复制代码
把Cell分离

  在实际的开发中,一般没有人会把Row(或者行)的绘制和    ListView放在一起。我们这里就演示如何把Row的绘制分离出去。  
  首先创建一个单独的文件,定义Cell:
  1. import React from 'react';
  2. import {
  3.   View,
  4.   Text,
  5.   TouchableHighlight,
  6.   StyleSheet
  7. } from 'react-native';
  8. export default class DemoCell extends React.Component {
  9.   render() {
  10.     return (
  11.       <View>
  12.         <TouchableHighlight onPress={this.props.onSelect}>
  13.           <View style={styles.row}>
  14.             <Text style={styles.text}>{this.props.rowData}</Text>
  15.           </View>
  16.         </TouchableHighlight>
  17.       </View>
  18.     );
  19.   }
  20. };
  21. const styles = StyleSheet.create({
  22.   row: {
  23.     flexDirection: 'row',
  24.     justifyContent: 'center',
  25.     padding: 10,
  26.     backgroundColor: '#F6F6F6',
  27.   },
  28.   text: {
  29.     flex: 1,
  30.   },
  31. });
复制代码
Row也是一个组件,是一个组件就可以在另外的组建里渲染。所以,单独定义的Row就是这么用的。
  回到    demoList.js文件。在    _renderRow方法中修改代码:  
  1. _renderRow(rowData: string, sectionID: number, rowID: number, highlightRow: (sectionID: number, rowID: number) => void) {
  2.     return (
  3.       // <TouchableHighlight onPress={() => {
  4.       //   this._pressRow(rowID);
  5.       //   highlightRow(sectionID, rowID);
  6.       // }}>
  7.       //   <View style={styles.row}>
  8.       //     <Text style={styles.text}>{rowData}</Text>
  9.       //   </View>
  10.       // </TouchableHighlight>
  11.       <DemoCell onSelect={() => {
  12.          this._pressRow(rowID);
  13.          highlightRow(sectionID, rowID);
  14.        }} rowData={rowData}/>
  15.     );
  16.   }
复制代码
结合网络请求

  ListView在实战中,除非是Settings之类的界面,数据都是从网络请求得到的。上一节中正好已经讲述了如何使用RN内置的fetch请求网络数据。这一节中就是用fetch来请求dribbble的数据。
  在使用dribbble的数据之前你需要注册,获得Access Token。这是请求认证所必须的。
  1. export default class DemoList extends React.Component {
  2.   constructor(props) {
  3.     super(props);
  4.     const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
  5.     this.state = {
  6.       isLoading: false,
  7.       isLoadingTail: false,
  8.       dataSource: new ListView.DataSource({
  9.         rowHasChanged: (row1, row2) => row1 !== row2,
  10.       }),
  11.       filter: this.props.filter,
  12.       queryNumber: 0,
  13.     };
  14.     //...略...
  15.   }
  16.   //...略...
  17.   _getShots(query: string) {
  18.     this.setState({
  19.       isLoading: true,
  20.       queryNumber: this.state.queryNumber + 1,
  21.       isLoadingTail: false,
  22.     });
  23.     api.getShotsByType(query, 1).then((responseData) => {
  24.       this.setState({
  25.         isLoading: false,
  26.         dataSource: this._getDataSource(responseData),
  27.       });
  28.     }).catch((error) => {
  29.       this.LOADING[query] = false;
  30.       this.resultsCache.dataForQuery[query] = undefined;
  31.       this.setState({
  32.           dataSource: this._getDataSource([]),
  33.           isLoading: false,
  34.       });
  35.     });
  36.   }
复制代码
还是在类    DemoList里,其他无关紧要的代码先略去。要紧的地方是需要注意在    constructor里设置state的时候    dataSource如何设置的。  
  state的改变会影响到组件的绘制。所以,在    _getShots方法里,开始请求之前先设置一个默认的state状态。在请求成功之后使用    setState设置一个,在catch到异常的时候再显示另外一个。  
  在    state里还有一个属性叫做    isLoading: false,。这个是影控制Loading视图的。在false的时候隐藏,在true的时候显示。  
  那么loading界面是什么样呢?
  1. <View style={{alignItems: 'center', justifyContent: 'center', flex: 1, backgroundColor: 'white'}}>
  2.     <ActivityIndicator animating={true}
  3.       style={[styles.centering]}
  4.       size="large"
  5.       color="#cccccc"
  6.     />
  7. </View>
复制代码
组合起来

  在类    DemoList里组合相关代码:  
  1. _renderView() {
  2.     if (this.state.isLoading) {
  3.       return (
  4.         <UNActivityIndicator loadingType={LOADING_TYPE.Large} />
  5.       );
  6.     }
  7.     return (
  8.       <View style={styles.container}>
  9.         <ListView
  10.           dataSource={this.state.dataSource}
  11.           renderRow={this._renderRow}
  12.           renderSeparator={this._renderSeparator}
  13.           automaticallyAdjustContentInsets={false}
  14.           />
  15.       </View>
  16.     );
  17.   }
复制代码
在renderView的时候,先检查    state.isLoading,如果需要loading视图,那么返回loading视图,其他的不返回。数据加载成功之后    state.isLoading被设置为false,那么显示ListView。  
  填坑完毕

  以上就是处理ListView和其中的Cell的一些常见问题的方法。
友荐云推荐




上一篇:高清屏概念解析与检测设备像素比的方法
下一篇:iTunes Remote (WebSocket + Applescript + React)
酷辣虫提示酷辣虫禁止发表任何与中华人民共和国法律有抵触的内容!所有内容由用户发布,并不代表酷辣虫的观点,酷辣虫无法对用户发布内容真实性提供任何的保证,请自行验证并承担风险与后果。如您有版权、违规等问题,请通过"联系我们"或"违规举报"告知我们处理。

我是逗比我骄傲 发表于 2016-10-13 03:06:58
人生最痛苦的事就是方便面涨价了。
回复 支持 反对

使用道具 举报

jm7vjdtx 发表于 2016-10-14 21:50:57
支持楼上的!
回复 支持 反对

使用道具 举报

5633453 发表于 2016-10-20 14:51:38
该去看看专家教授了
回复 支持 反对

使用道具 举报

恶魔??雪翼 发表于 2016-10-21 02:07:21
2016-10-21楼主还是蛮拼的。
回复 支持 反对

使用道具 举报

想你时天气不佳 发表于 2016-10-24 11:46:45
明明白白我的心,楼主赏我个沙发!
回复 支持 反对

使用道具 举报

*滑动验证:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

我要投稿

推荐阅读

扫码访问 @iTTTTT瑞翔 的微博
回页顶回复上一篇下一篇回列表手机版
手机版/CoLaBug.com ( 粤ICP备05003221号 | 文网文[2010]257号 )|网站地图 酷辣虫

© 2001-2016 Comsenz Inc. Design: Dean. DiscuzFans.

返回顶部 返回列表