基础篇章:关于 React Native 之 ListView 组件的讲解
RoseannaFor
8年前
<p>我们讲完ScrollView组件,其实顺其自然的就应该讲解ListView,对于前段和移动端的开发人员应该非常熟悉这样的控件吧,具体是做什么的,我感觉不用我讲了吧。我们来看看它怎么使用吧。</p> <p>大家好,我是ListView,我是React Native大家族中基础组件中,一个核心组件。我可以高效的展示垂直滚动的变化的数据列表,而且这个列表有一个特点就是结构和数据比较相似才可以哦。</p> <p>我和ScrollView那家伙不太相同,我更适于长列表数据,且元素个数可以增删。和ScrollView不同的是,我并不立即渲染所有元素,而是优先渲染屏幕上可见的元素。怎么样?是不是感觉我更聪明?</p> <p>我有两个必须的属性是dataSource和renderRow。dataSource是列表的数据源,而renderRow则逐个解析数据源中的数据,然后返回一个设定好格式的组件来渲染。举个例子:我最基本的使用方式就是创建一个ListView.DataSource数据源,然后给它传递一个普通的数据数组,再使用数据源来实例化一个ListView组件,并且定义它的renderRow回调函数,这个函数会接受数组中的每个数据作为参数,返回一个可渲染的组件(作为我的每一行)。</p> <p>记住:rowHasChanged函数也是我的必需属性。用于比较两行数据是否是同一个数据来判断某行数据是否变化了。</p> <h2><strong>官方简单例子</strong></h2> <pre> <code class="language-javascript">class MyComponent extends Component { constructor() { super(); 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>} /> ); } } </code></pre> <h2><strong>高级属性</strong></h2> <p>想我这么聪明的组件,我当然还支持一些高级的特性,比如:给每组数组加一个粘节标题,也就是类似于通讯录中其首字母会在滑动过程中吸附在屏幕上方,支持页眉和页脚,也就是可以在列表中添加头部和尾部。在到达列表尾部的时候调用回调函数(onEndReached),还有在视野内可见的数据变化时调用回调函数(onChangeVisibleRows),以及一些性能方面的优化。</p> <p>在我母亲制定的官方介绍中,这么说:有一些性能优化使得我ListView可以滚动的更加平滑,尤其是在动态加载可能很大(或者概念上无限长的)数据集的时候:</p> <ul> <li>只更新变化的行 - 提供了rowHasChanged函数可以告诉ListView它是否需要重绘一行数据。</li> <li>限制频率的行渲染 - 默认情况下,每次消息循环只有一行会被渲染(可以用pageSize属性配置)。这把较大的工作分散成小的碎片,以降低因为渲染而导致丢帧的可能性。</li> </ul> <h2><strong>基本属性</strong></h2> <p>介绍完我的高级功能特性,再来看看我的基本属性吧,懂了这些,你可以玩我跟玩孩子似的,运用自如。</p> <p>我前面说了,我这人比ScrollView那家伙聪明多了,所以它的属性,我都能用,这里关于和ScrollView相同的属性就不赘述了。看看我的与众不同,比它聪明在哪吧?</p> <ul> <li>dataSource 传入的数据源</li> <li>enableEmptySections bool 空内容的sections是否被渲染,默认是会渲染</li> <li>initialListSize number 指定在组件刚挂载的时候渲染多少行数据。用这个属性来确保首屏显示合适数量的数据,而不是花费太多帧逐步显示出来。</li> <li>onChangeVisibleRows function 当可见的行发生变化的时候回调该函数。visibleRows参数对所有可见的行为{selectionID:{rowId:true}}的形式,changedRow参数对已经改变可见的行为{selectionID:{rowID:true|false}}。该值true代表可见,false代表在视图之外不可见的行。</li> <li>onEndReached function 当所有的数据都已经渲染过,并且列表被滚动到距离最底部不足onEndReachedThreshold个像素的距离时调用。原生的滚动事件会被作为参数传递。译注:当第一次渲染时,如果数据不足一屏(比如初始值是空的),这个事件也会被触发。</li> <li>onEndReachedThreshold number 调用onEndReached之前的临界值,单位是像素。</li> <li>pageSize number 每一次事件的循环渲染的行数。</li> <li>removeClippedSubviews bool 用于提升大列表的滚动性能。需要给行容器添加样式overflow:’hidden’。(Android已默认添加此样式)。此属性默认开启。</li> <li>renderFooter function 方法 ()=>renderable ,在每次渲染过程中头和尾总会重新进行渲染。如果发现该重新绘制的性能开销比较大的时候,可以使用StaticContainer容器或者其他合适的组件。在每一次渲染过程中Footer(尾)该会一直在列表的底部,header(头)该会一直在列表的头部</li> <li>renderHeader function 与上同理</li> <li>renderRow function (rowData, sectionID, rowID, highlightRow) => renderable 从数据源(Data source)中接受一条数据,以及它和它所在section的ID。返回一个可渲染的组件来为这行数据进行渲染。默认情况下参数中的数据就是放进数据源中的数据本身,不过也可以提供一些转换器。如果某一行正在被高亮(通过调用highlightRow函数),ListView会得到相应的通知。当一行被高亮时,其两侧的分割线会被隐藏。行的高亮状态可以通过调用highlightRow(null)来重置。</li> <li>renderScrollComponent function 返回在列表行呈现的滚动组件的功能。默认为ScrollView。</li> <li>renderSectionHeader function (sectionData, sectionID) => renderable 如果提供了此函数,会为每个小节(section)渲染一个粘性的标题。粘性是指当它刚出现时,会处在对应小节的内容顶部;继续下滑当它到达屏幕顶端的时候,它会停留在屏幕顶端,一直到对应的位置被下一个小节的标题占据为止。</li> <li>renderSeparator function 如果提供了此属性,一个可渲染的组件会被渲染在每一行下面,除了小节标题的前面的最后一行。在其上方的小节ID和行ID,以及邻近的行是否被高亮会作为参数传递进来。</li> <li>scrollRenderAheadDistance number 当该行进入屏幕多少像素以内之后就开始渲染该行</li> <li>stickyHeaderIndices [number] ios独有 一个子视图下标的数组,用于决定哪些成员会在滚动之后固定在屏幕顶端。</li> </ul> <h2><strong>实例演示</strong></h2> <h3><strong>效果图</strong></h3> <p>来,看看我美不美,好不好用,我的真实面目如下:</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/39288ab964d1ce06bc66c9430892f78d.gif"></p> <h3><strong>代码</strong></h3> <pre> <code class="language-javascript">import React, { Component } from 'react'; import { AppRegistry, StyleSheet, Text, ListView, Image, TouchableHighlight, View } from 'react-native'; class ListViewDemo extends Component { constructor(props) { super(props); const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2}); this.state = { dataSource: ds.cloneWithRows(this._genRows(-1)) }; } _genRows(flag){ const dataBlob = []; for(let i = 0 ; i< 88 ; i ++ ){ if(i == flag){ dataBlob.push("非著名程序员+我被打了"+i); }else{ dataBlob.push("非著名程序员"+i); } } return dataBlob; } render() { return ( <ListView dataSource={this.state.dataSource} renderRow={this._renderRow.bind(this)} /> ); } _renderRow (rowData,sectionID, rowID) { return ( <TouchableHighlight onPress={() => { this._pressRow(rowData,rowID); }} underlayColor='red' > <View> <View style={styles.row}> <Image style={{width:40,height:40}} source={require('./Thumbnails/head.jpg')}/> <Text style={{flex:1,fontSize:20,marginLeft:20}}> {rowData} </Text> </View> </View> </TouchableHighlight> ); } _pressRow(rowData,rowID){ alert(rowData); this.setState({dataSource: this.state.dataSource.cloneWithRows( this._genRows(rowID) )}); } } const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: '#F5FCFF', }, row: { flexDirection: 'row', justifyContent: 'center', alignItems:'center', padding: 10, }, }); AppRegistry.registerComponent('ListViewDemo', () => ListViewDemo); </code></pre> <p>ok,关于ListView组件的讲解大概就先讲到这里,更多的内容和实例,欢迎大家移步到官网,看文档,但是官网上大部分的例子用的是es5的语法。</p> <p> </p> <p> </p> <p>来自:http://godcoder.me/2016/11/02/基础篇章:关于 React Native 之 ListView 组件的讲解/</p> <p> </p>