当前位置: 首页 > 编程笔记 >

react native带索引的城市列表组件的实例代码

唐兴思
2023-03-14
本文向大家介绍react native带索引的城市列表组件的实例代码,包括了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'
  }
});

最终效果:

 

 

最后是界面的绘制,这里就不多说了,大家可以下载源码自行查看。源码地址: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

  • 我的城市是一款增量点击游戏。你需要点击收获原始资源,然后注意: 要用现金购买东西 研究需要脑力 运行事物需要能量 矿石可提供基础材料 水可作为消耗品 犯罪会让你付出代价...(尚未实施) 污染会使你生病