近期,在完成一个含有索引列表功能的项目。效果如图所示:
首先,我用的是react native 所提供的 ListView 这个组件(由于这个组件已经过期,而且此列表为分组列表,所以建议大家使用react native 官网所提供的 SectionList 组件,后面会有demo来讲解如何使用),然后计算每个组的高度,然后存起来,在点击索引的时候,用 组件所提供的scrollTo 方法来进行滑动调相应的位置。我的具体实现为:
(1)用ListView组件,将列表展示出来
this._listView = listView}
contentContainerStyle={styles.contentContainer}
dataSource={this.state.dataSource}
renderRow={this._renderListRow.bind(this)}
renderSectionHeader={this._renderListSectionHeader.bind(this)}
enableEmptySections={true}
initialListSize={500}/>
(2) /*分组的组名*/
_renderListSectionHeader(sectionData, sectionID) {
组名的渲染,具体代码,在后面看后面提供的具体demo
}
(3)/*主体数据列表*/
_renderListRow(cityJson, rowId) {
每一行数据的渲染,这里分为了关键字为字母和非字母两种渲染格式。具体代码,看后面提供的具体demo
}
(4){/*索引*/}
索引采用绝对定位的方式,将索引定位到右侧。具体代码,看后面提供的具体demo
最后实现的效果图,如下:
具体的demo地址: https://github.com/LQ0611/IndexList.git
如果想看效果,请将本包引入你的项目中,并调用包中 test-MainPage 页面;如果想实际使用,请看包中 readme 文件。
在实际使用中,由于出入的数据在几百个,数据量过大,而且由于要计算各个组的高度,所以这些数据必须第一次时就要全部渲染,所以这个组件在进入的时候,非常慢。因此,为了改善进入的体验,而有了改进版,如下介绍。
在改进版中,我们使用的组件是:LargeList ,关于这个组件的出处,有兴趣的可以看一下 https://bolan9999.github.io/react-native-largelist/
(1)将数据展示出来
(this._listView = ref)} //后面在滚动时,用它来做标识,明确操作的是哪一个
reloadData={this.state.contacts} //传入的数据
numberOfSections={()=>this.state.contacts.length} //本数据中有多少个组
numberOfRowsInSection={section => this.state.contacts[section].info.length} //某一组中,有多少条数据
heightForCell={()=>this.state.heightForCell} //渲染每一条数据时,所占的高是多少
heightForSection={()=>this.state.heightForSection} //渲染时,每个组名所占的高是多少
renderSection={this.renderSection.bind(this)} //组名的渲染方法
renderCell={this._renderItem.bind(this)} //组内数据的渲染方法
renderFooter={this.renderFooter.bind(this)} //在滑动到列表底部时,在列表底部所显示的提示内容
/>
(2)滚动的计算与实现
首先,将我们数据中的header取出,并通过toUpperCase方法,转换成大写
然后,将取出的组名存放到一个数组中备用
在然后,根据统计出的每个组有多少条数据 * 设定好的数据的高度 + 多少个组* 每个组的高度,将计算得到的结果,保存进数据,当点击某个索引是,就能直接得到要滚动 的距离
this.state.contacts.map(contacts => {
let key = contacts.header.toUpperCase();
if (dataBlob[key]) {
let subList = dataBlob[key];
subList.push(contacts);
} else {
let subList = [];
subList.push(contacts);
dataBlob[key] = subList;
}
});
let sectionIDs = Object.keys(dataBlob);
/*计算高度*/
let rowIDs = sectionIDs.map((sectionID,i) => {
let thisRow = [];
let count = this.state.contacts[i].info.length;
console.log("count:",count);
for (let ii = 0; ii < count; ii++) {
thisRow.push(ii);
}
let eachheight = this.state.heightForSection + this.state.heightForCell * thisRow.length;
//if (sectionID === key_hot || sectionID === key_now || sectionID === key_last_visit) {
totalheight.push(eachheight);
return thisRow;
});
滚动事件:
_scrollTo(index, letter) {
this.refs.toast.close();
let position = 0;
for (let i = 0; i < index; i++) {
position += totalheight[i]
}
console.log("position",position)
this._listView.scrollTo({x:0,y:position+5}) ; //滚动方法
this.refs.toast.show(letter, DURATION.LENGTH_SHORT); //在点击某个索引时 ,屏幕上回短暂的显示此索引的字母
}
(3)索引的实现
{/*索引*/}
索引也是采用绝对定位到右边。详情请看后面的具体的demo
(4)组名的展示方法
/*组名*/
renderSection(section){
具体的展示代码请看下面的demo
}
(5)组内数据的展示
/*主体数据展示*/
_renderItem (section: number, row: number){
具体的展示代码请看下面的demo
}
具体的demo地址:https://github.com/LQ0611/IndexList-v2.git
效果图: