React Native ListView sticky效果实现

React Native中,ScrollView组件可以使用 stickyHeaderIndices 轻松实现 sticky 效果。

而使用ListView组件时,使用 stickyHeaderIndices 则不生效。

在IOS中的ListView的内部结构,实际是由多个Section组成,最典型的案例就是iphone手机的通讯录,滚动时每个section header会吸顶。

而在web端,使用 position : -weblit-sticky 实现的吸顶效果,也是类似的原理。具体可以看下之前的文章: 《position:sticky 使用条件分析》 .

好了,废话不多。在ListView中实现 sticky ,需要使用 cloneWithRowsAndSections 方法,将 dataBlob (object), sectionIDs (array),rowIDs (array) 三个值传进去即可。

dataBlob

dataBlob 包含ListView所需的所有数据(section header 和 rows),在ListView渲染数据时,使用 getSectionData 和 getRowData 来渲染每一行数据。 dataBlob 的 key 值包含 sectionID rowId

sectionIDs

sectionIDs 用于标识每组section。

rowIDs

rowIDs 用于描述每个 section 里的每行数据的位置及是否需要渲染。在ListView渲染时,会先遍历 rowIDs 获取到对应的 dataBlob 数据。

根据上面3个数据的定义,模拟出对应的数据结构如下:


var dataBlob = {
     'sectionID1' : { ...section1 data },
     'sectionID1:rowID1' : { ...row1 data },
     'sectionID1:rowID2' : { ..row2 data },
     'sectionID2' : { ...section2 data },
     'sectionID2:rowID1' : { ...row1 data },
     'sectionID2:rowID2' : { ..row2 data },
     ...
}

var sectionIDs = [ 'sectionID1', 'sectionID2', ... ]

var rowIDs = [ [ 'rowID1', 'rowID2' ], [ 'rowID1', 'rowID2' ], ... ]

在 DataSource 中,告诉ListView获取row和section的方法。


var getSectionData = (dataBlob, sectionID) => {
      return dataBlob[sectionID];
 }
var getRowData = (dataBlob, sectionID, rowID) => {
      return dataBlob[sectionID + ':' + rowID];
}
this.ds = new ListView.DataSource({
      getSectionData: getSectionData,
      getRowData: getRowData,
      rowHasChanged: (r1, r2) => r1 !== r2,
      sectionHeaderHasChanged: (s1, s2) => s1 !== s2
})

最后将数据传进ListView

 this.dataSource.cloneWithRowsAndSections(dataBlob, sectionIDs, rowIDs) 

最终效果如图:

1

完整代码示例可查看: https://github.com/hugohua/rn-listview-example

参考文章:

http://moduscreate.com/react-native-listview-with-section-headers/