城市列表选择是很多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' } });
最终效果:
最后是界面的绘制,这里就不多说了,大家可以下载源码自行查看。源码地址:react-native-city_jb51.rar
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持小牛知识库。
新增或编辑员工时,建议您录入员工常驻城市信息,便于您后续设置用车制度。 请按照以下列表规范进行填写,如:填写“北京”而非“北京市” 具体列表内容如下: 北京 深圳 广州 上海 杭州 武汉 天津 沈阳 郑州 西安 南京 济南 青岛 大连 合肥 哈尔滨 成都 重庆 昆明 宁波 东莞 石家庄 苏州 长沙 长春 太原 洛阳 西宁 烟台 兰州 厦门 南宁 福州 泉州 佛山 三亚 南昌 徐州 唐山 呼和浩特
当跨城接送选择以上选项时,可允许跨城接送服务的城市列表如下: 1.西安-咸阳 2.深圳-东莞 3.廊坊-北京 4.佛山-广州 5.东莞-广州 6.苏州-上海 7.苏州-无锡 8.保定-石家庄 9.汕头-揭阳-潮州
Since 8.1 getCities getCities用来呼出城市选择列表 使用方法 AlipayJSBridge.call('getCities', function (result) { console.log(result); }); 代码演示 基本使用演示 <h1>点击打开选择城市</h1> <a href="#" class="btn J_demo">打开城市列表</a> <s
本文向大家介绍原生js封装二级城市下拉列表的实现代码,包括了原生js封装二级城市下拉列表的实现代码的使用技巧和注意事项,需要的朋友参考一下 闲的蛋疼,封装了个二级城市下拉 先保证html里有 然后引用js 最终通过new SelectCity() 调用。 懒得分离这里js就写在页面了 一言不合上代码 以上就是小编为大家带来的原生js封装二级城市下拉列表的实现代码的全部内容了,希望大家多多支持
获取城市列表 说明 获取全量城市列表 地址URL /v1/common/Cities/getAll 支持格式 {url}?k1=v1&k2=v2&k3=v3&... HTTP请求方式 GET 是否需要登录 是 关于登录授权,参见 如何登录授权 访问授权限制 暂无 请求参数 名称 类型 必选 描述 client_id string yes 申请应用时分配的APP_KEY access_token s
我的城市是一款增量点击游戏。你需要点击收获原始资源,然后注意: 要用现金购买东西 研究需要脑力 运行事物需要能量 矿石可提供基础材料 水可作为消耗品 犯罪会让你付出代价...(尚未实施) 污染会使你生病