案例技术点分析:
- 在React Native中,ScrollView组件可以使用 stickyHeaderIndices 轻松实现 sticky 效果;而使用ListView组件时,使用 stickyHeaderIndices 则不生效。
- 如何实现滚动时每个section header会吸顶?
- 在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 数据。
模拟对应的数据结构模型
//模拟IOS的通讯录 import React,{ Component } from 'react'; import { AppRegistry,StyleSheet,Text,View,Image,ListView,TouchableOpacity } from 'react-native'; //模拟数据 var ListData={ data:[ //组一 { cars:[ { "icon":"QQ","name":"奥迪" },{ "icon":"QQ","name":"阿尔法" },"name":"阿斯顿马丁" },"name":"ALPIMA" },"name":"安凯客车" },"name":"ARCFOX" } ],title:"A" },// 组二 { cars:[ { "icon":"QQ","name":"保时捷" },"name":"本田" },"name":"别克" },"name":"奔驰" },"name":"宝马" },"name":"宝骏" },"name":"比亚迪" },"name":"标志" },"name":"北京" },"name":"北汽幻速" },"name":"宝沃" },"name":"奔腾" },"name":"北汽绅宝" },"name":"宾利" },"name":"比速汽车" },"name":"北汽制造" },"name":"北汽威旺" },"name":"北汽新能源" },"name":"巴博斯" },"name":"布加迪" },"name":"北汽到达" } ],title:"B" },// 组三 { cars:[ { "icon":"QQ","name":"长安" },"name":"长安酷尚" },"name":"长城" },"name":"长安轻型车" },"name":"昌河" },"name":"成功汽车" },"name":"长安跨越" } ],title:"C" } ] } var ListViewDemo3=React.createClass({ getInitialState(){ //获取组中的数据 var getSectionData=(dataBlob,sectionID) => { return dataBlob[sectionID]; } //获取行中的数据 var getRowData=(dataBlob,sectionID,rowID)=>{ return dataBlob[sectionID+":"+rowID] }; return{ dataSource:new ListView.DataSource({ getSectionData:getSectionData,//获取组中的数据 getRowData:getRowData,//获取行中的数据 rowHasChanged:(r1,r2) => r1 !== r2,sectionHeaderHasChanged:(s1,s2) => s1 !== s2,}) } },//每一行中的数据 renderRow(rowData){ return( <TouchableOpacity activeOpacity={0.5}> <View style={styles.rowStyle}> <Image style={styles.rowImg} source={{uri:rowData.icon}}/> <Text>{rowData.name}</Text> </View> </TouchableOpacity> ) },//每一组中的数据 renderSectionHeader(sectionData,sectionID){ return( <View style={styles.sectionHeader}> <Text style={{marginLeft:10,marginTop:5,color:"red"}}>{sectionData}</Text> </View> ) },render(){ return ( <View style={styles.outerView}> {/*头部*/} <View style={styles.headerView}> <Text style={{color:"#fff",fontSize:25}}>see MyGo品牌</Text> </View> <ListView dataSource={this.state.dataSource} renderRow={this.renderRow} renderSectionHeader={this.renderSectionHeader} /> </View> ) },//复杂的操作:数据请求或者异步操作等等 componentDidMount(){ //调用JSON数据 this.loadDataFromJson(); },loadDataFromJson(){ //拿到JSON数据 var jsonData=ListData.data; //定义一些变量 var dataBlob={},sectionIDs=[],rowIDs=[],cars=[]; //遍历 for(var i=0;i<jsonData.length;i++){ //1、把组号放入sectionIDs数组中 sectionIDs.push(i); //2、把组中的内容放入dataBlob对象中 dataBlob[i]=jsonData[i].title; //3、取出该组中所有的车 cars = jsonData[i].cars; rowIDs[i]=[]; //4、遍历所有的车数组 for(var g=0;g<cars.length;g++){ //把行号放入rowID rowIDs[i].push(g); //把每一行的内容放入dataBlob对象中 dataBlob[i+":"+g]=cars[g]; } } //更新状态 this.setState({ dataSource:this.state.dataSource.cloneWithRowsAndSections(dataBlob,sectionIDs,rowIDs) }) } }); const styles = StyleSheet.create({ outerView:{ flex:1 },headerView:{ height:64,backgroundColor:"orange",justifyContent:"center",alignItems:"center" },rowStyle:{ flexDirection:"row",alignItems:"center",padding:10,borderBottomColor:"#e8e8e8",borderBottomWidth:0.5 },rowImg:{ width:70,height:70,marginRight:10 },sectionHeader:{ backgroundColor:"#e8e8e8",height:30,justifyContent:"center" } }); export default ListViewDemo3;