此文章中,包括简单的布局,九宫格布局和头视图的使用小demo
前言
在iOS开发中,用的最多的一个控件就是TableView,ListView和TableView实现的效果一下,是React Native中的核心组件,高效的用于显示一个可以垂直滚动变化的数据列表。
TableView的工作原理是:先加载UI,有数据源之后再刷新界面。
ListView的工作原理是:想创建一个ListView.DataSource数据源,然后给他传递一个普通的的数据组,在使用数据源来实例化一个ListView组件。使用renderRow回调函数,接受数组中的每个数组作为参数,返回一个可渲染的组件。
一、ListView常用属性
ListView 继承ScrollerView相关的样式属性
DataSource 数据属性
initialListSize number
控制组件刚挂载的时候渲染多少行数据,用来确保首屏显示合适数量的数据,而不是花费太多帧逐步显示出来。
onEndReachedThreshold number
设置什么时候偏移量达到设置的临界值调用onEndReached
pageSize number
每帧渲染的行数
removeClippedSubviews bool
该属性用于提供大数据列表的滚动性能。该使用的时候需要给每一行(row)的布局添加over:'hidden'样式。该属性默认是开启状态。
scrollRenderAheadDistance number
当一行接近屏幕范围多少像素之内的时候,开始渲染这一行。
IOS stickyHeaderIndices[number]
一个子视图下标的数组,用于决定哪些成员会在滚动之后固定在屏幕顶端。
function属性
onChangeVisibleRows (visibleRows,changedRows)=>void
当可见的行发生变化的时候回调该方法。
onEndReached
当所有的数据都已经渲染过,并且列表被滚动到距离最底部不足onEndReachedThreshold个像素的距离时调用原生的滚动事件会被作为参数传递。
注意:当第一次渲染时,如果数据不足一屏(比如初始值是空的),这个事件也会被触发。
renderFooter ()=>renderable
在每次渲染过程中头和尾总会重新进行渲染。如果发现该重新绘制的性能开销比较大的时候,可以使用StaticContainer容器或者其他合适的组件。
renderHeader 在每一次渲染过程中Footer(尾)该会一直在列表的底部,header(头)该会一直在列表的头部,用法同上。
renderRow (rowData,sectionID,rowID,highlightRow)=>renderable
该方法有四个参数,其中分别为数据源中一条数据,分组的ID,行的ID,以及标记是否是高亮选中的状态信息。
renderScrollComponent (props)=>renderable
该方法可以返回一个可以滚动的组件。默认该会返回一个ScrollView
renderSectionHeader (sectionData,sectionID)=>renderable
如果设置了该方法,这样会为每一个section渲染一个粘性的header视图。该视图粘性的效果是当刚刚被渲染开始的时候,该会处于对应的内容的顶部,然后开始滑动的时候,该会跑到屏幕的顶端。直到滑动到下一个section的header(头)视图,然后被替代为止。
renderSeparator (sectionID,rowID,adjacentRowHighlighted)=>renderable
如果设置该方法,会在被每一行的下面渲染一个组件作为分隔。除了每一个section分组的头部视图前面的最后一行。
方法
导出一些用于性能分析的数据。
scrollTo
滚动到指定的X,Y偏移处,可以指定是否加上过渡动画。
二、ListView高级特性
2.1给每段/组数据天天以后带有粘性的头部。
2.2在列表头部和尾部增加单独的内容,在到达列表尾部的时候调用函数(onEndReached),还有在视野可见的数据变化时调用回调函数(onChangeVisibleRows)。
2.3在性能方面优化
只更新变化的行 - 提供给数据源的rowHasChanged函数可以告诉ListView中它是否需要重绘一行数据(即:数据是否发生了变化)参见ListViewDataSource
限制频率的行渲染-默认情况下,每次消息循环只有一行会被渲染(用可以pageSize属性配置)这把较大的工作分散成小的碎片,以降低因为渲染而导致丢帧的可能性。
三、ListView常用Demo
3.1简单的电商demo
3.1.1listView的使用步骤:
代码截图:
运行效果:
这种比较简单,只要到时候改变返回的row中的View的样式即可
3.2九宫格demo
使用ListView实现九宫格的原理就是,一个listView,将cell通过flex布局实现,主轴方向的改变,然后设置,每个cell的布局得到。
注意:在这个过程中,实现row主轴的改变后,实现多行显示总是不行,原因是removeClippedSubviews={false}的默认状态是ture是隐藏的。
3.2.1 代码截图:
运行截图:
3.3分组带有头视图的demo
DataSource 的方法解析及技术分析
1.数组的提取和更新方法
clone方法会自动提取新数据并进行逐行对比(使用rowHasChanged方法中的策略),这样ListView就知道哪些行需要重新渲染了。
cloneWithRows(dataBlob(原始数据), rowIdentities(二维数组))
cloneWithRowsAndSections(dataBlob(原始数据), sectionIdentities(数组,包含了section标识符), rowIdentities(数组))
section标题和行数据提供自定义的提取方法和hasChanged比对方法。如果不提供,则会使用默认的defaultGetRowData和defaultGetSectionHeaderData方法来提取行数据和section标题。
默认的提取函数处理一下的数据类型
{ sectionID_1: { rowID_1: rowData1, ... }, ... } =>>> key:{}
{ sectionID_1: [ rowData1, rowData2, ... ], ... } =>>> key:[]
[ [ rowData1, rowData2, ... ], ... ] = >>>> [[],[]....]
通过构造函数提取数组的方法一共有四种:
(1).getRowData(sectionIndex, rowIndex) 返回渲染行数所需的数据(指定如何从原始dataBlob中提取数据)。
(2).getSectionHeaderData(dataBlob, sectionID); 获取section标题数据。
(3)rowHasChanged(prevRowData, nextRowData); 通过对比创建数组
(4). sectionHeaderHasChanged(prevSectionData, nextSectionData); 通过对比创建
2.其他方法
getRowCount() 获取行数
getRowAndSectionCount() 获取原始数据的分组个数
rowShouldUpdate(sectionIndex, rowIndex) 返回值表明某行数据是否已变更,需要重新渲染。
getRowData(sectionIndex, rowIndex) 返回渲染行所需的数据(指定如何从原始dataBlob中提取数据)。
getSectionIDForFlatIndex(index) 给定索引值,求其对应sectionID。如果查找不到则返回null。
getSectionLengths() 返回一个数组,包含每个section的行数量。
sectionHeaderShouldUpdate(sectionIndex) 返回值用于说明section标题是否需要重新渲染。
看到上边的大家可能还是蒙蒙的,简单的说就说:
DataBlob就是原始数据就是一个大的字典{
sectionID1:{},或者[]
}
sectionIDs = ['sectionID1',sectionID2',sectionID3'.......] 每组的标题
rowIDS = [[row1,row2],[row1,row2],[row1,row2],[row1,row2].....] 每组的数据
第一步需要在datasource中,设置ListView获取row和section方法
第二步因为需要对数据进行循环拆分,组合成dataBlob需要的数据样式属于耗时操作,放到componentDidMount方法中,完成操作后刷新状态,将数据传到listView的render()方法中。
第三步,返回相关函数,设置属性样式布局
代码截图
运行结果:
完整demo请https://github.com/nanaLxs/ListView-demo下载。如果感觉可以请star。在这里谢谢啦!!
网友评论
width:width,
//设置横向布局
flexDirection:'row',
//设置换行显示
flexWrap:'wrap',
},
iconStyle:{
width:80,
height:80,
},
cellViewStyle:{
width:100,
height:100,
marginLeft:marginX,
marginTop:20,
alignItems:'center'//居中显示
}