react native带索引的城市列表组件的实例代码
程序员文章站
2022-11-25 09:29:20
城市列表选择是很多app共有的功能,比如典型的美图app。那么对于react native怎么实现呢?
要实现上面的效果,首先需要对界面的组成简单分析,界面的数...
城市列表选择是很多app共有的功能,比如典型的美图app。那么对于react native怎么实现呢?
要实现上面的效果,首先需要对界面的组成简单分析,界面的数据主要由当前城市,历史访问城市和热门城市组成,所以我们在提供json数据的时候就需要将数据分为至少3部分。
const all_city_list = data_json.allcitylist; const hot_city_list = data_json.hotcitylist; const last_visit_city_list = data_json.lastvisitcitylist;
而要实现字母索引功能,我们需要自定义一个控件,实现和数据的绑定关系,自定义组件代码如下:
cityindexlistview.js
'use strict'; import react, {component} from 'react'; import { stylesheet, view, text, touchableopacity, listview, dimensions, } from 'react-native'; import toast, {duration} from './toastutil' const sectionheight = 30; const rowheight = 40; const rowheight_box = 40; var totalheight = []; //每个字母对应的城市和字母的总高度 const {width, height} = dimensions.get('window'); var that; const key_now = '当前'; const key_last_visit = '最近'; const key_hot = '热门'; export default class cityindexlistview extends component { constructor(props) { super(props); var getsectiondata = (datablob, sectionid) => { return sectionid; }; var getrowdata = (datablob, sectionid, rowid) => { return datablob[sectionid][rowid]; }; let all_city_list = this.props.allcitylist; let current_city_list = this.props.nowcitylist; let last_visit_city_list = this.props.lastvisitcitylist; let hot_city_list = this.props.hotcitylist; let letterlist = this._getsortletters(all_city_list); let datablob = {}; datablob[key_now] = current_city_list; datablob[key_last_visit] = last_visit_city_list; datablob[key_hot] = hot_city_list; all_city_list.map(cityjson => { let key = cityjson.sortletters.touppercase(); if (datablob[key]) { let sublist = datablob[key]; sublist.push(cityjson); } else { let sublist = []; sublist.push(cityjson); datablob[key] = sublist; } }); let sectionids = object.keys(datablob); let rowids = sectionids.map(sectionid => { let thisrow = []; let count = datablob[sectionid].length; for (let ii = 0; ii < count; ii++) { thisrow.push(ii); } let eachheight = sectionheight + rowheight * thisrow.length; if (sectionid === key_hot || sectionid === key_now || sectionid === key_last_visit) { let rownum = (thisrow.length % 3 === 0) ? (thisrow.length / 3) : parseint(thisrow.length / 3) + 1; console.log('sectionids===>' + sectionids + ", rownum=====>" + rownum); eachheight = sectionheight + rowheight_box * rownum; } totalheight.push(eachheight); return thisrow; }); let ds = new listview.datasource({ getrowdata: getrowdata, getsectionheaderdata: getsectiondata, rowhaschanged: (row1, row2) => row1 !== row2, sectionheaderhaschanged: (s1, s2) => s1 !== s2 }); this.state = { datasource: ds.clonewithrowsandsections(datablob, sectionids, rowids), letters: sectionids }; that = this; } _getsortletters(datalist) { let list = []; for (let j = 0; j < datalist.length; j++) { let sortletters = datalist[j].sortletters.touppercase(); let exist = false; for (let xx = 0; xx < list.length; xx++) { if (list[xx] === sortletters) { exist = true; } if (exist) { break; } } if (!exist) { list.push(sortletters); } } return list; } _citynameclick(cityjson) { // alert('选择了城市====》' + cityjson.id + '#####' + cityjson.name); this.props.onselectcity(cityjson); } _scrollto(index, letter) { this.refs.toast.close(); let position = 0; for (let i = 0; i < index; i++) { position += totalheight[i] } this._listview.scrollto({y: position}); this.refs.toast.show(letter, duration.length_short); } _renderrightletters(letter, index) { return ( <touchableopacity key={'letter_idx_' + index} activeopacity={0.6} onpress={() => { this._scrollto(index, letter) }}> <view style={styles.letter}> <text style={styles.lettertext}>{letter}</text> </view> </touchableopacity> ); } _renderlistbox(cityjson, rowid) { return ( <touchableopacity key={'list_item_' + cityjson.id} style={styles.rowviewbox} onpress={() => { that._citynameclick(cityjson) }}> <view style={styles.rowdatabox}> <text style={styles.rowdatatextbox}>{cityjson.name}</text> </view> </touchableopacity> ); } _renderlistrow(cityjson, rowid) { console.log('rowid===>' + rowid + ", cityjson====>" + json.stringify(cityjson)); if (rowid === key_now || rowid === key_hot || rowid === key_last_visit) { return that._renderlistbox(cityjson, rowid); } return ( <touchableopacity key={'list_item_' + cityjson.id} style={styles.rowview} onpress={() => { that._citynameclick(cityjson) }}> <view style={styles.rowdata}> <text style={styles.rowdatatext}>{cityjson.name}</text> </view> </touchableopacity> ) } _renderlistsectionheader(sectiondata, sectionid) { return ( <view style={styles.sectionview}> <text style={styles.sectiontext}> {sectiondata} </text> </view> ); } render() { return ( <view style={styles.container}> <view style={styles.listcontainner}> <listview ref={listview => this._listview = listview} contentcontainerstyle={styles.contentcontainer} datasource={this.state.datasource} renderrow={this._renderlistrow} rendersectionheader={this._renderlistsectionheader} enableemptysections={true} initiallistsize={500}/> <view style={styles.letters}> {this.state.letters.map((letter, index) => this._renderrightletters(letter, index))} </view> </view> <toast ref="toast" position='top' positionvalue={200} fadeinduration={750} fadeoutduration={1000} opacity={0.8}/> </view> ) } } const styles = stylesheet.create({ container: { // paddingtop: 50, flex: 1, flexdirection: 'column', backgroundcolor: '#f4f4f4', }, listcontainner: { height: dimensions.get('window').height, marginbottom: 10 }, contentcontainer: { flexdirection: 'row', width: width, backgroundcolor: 'white', justifycontent: 'flex-start', flexwrap: 'wrap' }, letters: { position: 'absolute', height: height, top: 0, bottom: 0, right: 10, backgroundcolor: 'transparent', // justifycontent: 'flex-start', // alignitems: 'flex-start' alignitems: 'center', justifycontent: 'center' }, letter: { height: height * 4 / 100, width: width * 4 / 50, justifycontent: 'center', alignitems: 'center' }, lettertext: { textalign: 'center', fontsize: height * 1.1 / 50, color: '#e75404' }, sectionview: { paddingtop: 5, paddingbottom: 5, height: 30, paddingleft: 10, width: width, backgroundcolor: '#f4f4f4' }, sectiontext: { color: '#e75404', fontweight: 'bold' }, rowview: { height: rowheight, paddingleft: 10, paddingright: 10, borderbottomcolor: '#f4f4f4', borderbottomwidth: 0.5 }, rowdata: { paddingtop: 10, paddingbottom: 2 }, rowdatatext: { color: 'gray', width: width }, rowviewbox: { height: rowheight_box, width: (width - 30) / 3, flexdirection: 'row', backgroundcolor: '#ffffff' }, rowdatabox: { borderwidth: 1, bordercolor: '#dbdbdb', margintop: 5, marginbottom: 5, paddingbottom: 2, marginleft: 10, marginright: 10, flex: 1, justifycontent: 'center', alignitems: 'center' }, rowdatatextbox: { margintop: 5, flex: 1, height: 20 } });
然后在头部还需要实现一个搜索框。
searchbox.js
'use strict'; import react, {component} from 'react'; import { view, textinput, stylesheet, platform, } from 'react-native'; export default class searchbox extends component { constructor(props) { super(props); this.state = { value: '' }; } onendeditingkeyword(vv) { console.log(vv); } onchanegetextkeyword(vv) { console.log('onchanegetextkeyword', vv); this.setstate({value: vv}); this.props.onchanegetextkeyword(vv); } render() { return ( <view style={styles.container}> <view style={styles.inputbox}> <view style={styles.inputicon}> </view> <textinput ref="keyword" autocapitalize="none" value={this.props.keyword} onchangetext={this.onchanegetextkeyword.bind(this)} returnkeytype="search" maxlength={20} style={styles.inputtext} underlinecolorandroid="transparent" placeholder={'输入城市名或拼音查询'}/> </view> </view> ) } } const styles = stylesheet.create({ container: { margintop: 5, marginbottom: 5, backgroundcolor: '#ffffff', flexdirection: 'row', height: platform.os === 'ios' ? 35 : 45, borderbottomwidth: stylesheet.hairlinewidth, borderbottomcolor: '#cdcdcd', paddingbottom: 5 }, inputbox: { height: platform.os === 'ios' ? 30 : 40, marginleft: 5, marginright: 5, flex: 1, flexdirection: 'row', backgroundcolor: '#e6e7e8' }, inputicon: { margin: platform.os === 'ios' ? 5 : 10 }, inputtext: { alignself: 'flex-end', margintop: platform.os === 'ios' ? 0 : 0, flex: 1, height: platform.os === 'ios' ? 30 : 40, marginleft: 2, marginright: 5, fontsize: 12, lineheight: 30, textalignvertical: 'bottom', textdecorationline: 'none' } });
最终效果:
最后是界面的绘制,这里就不多说了,大家可以下载源码自行查看。源码地址:
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
上一篇: 详解tween.js的使用教程