全网整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:400-708-3566

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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。


# react  # native城市列表  # native  # 带索引城市列表  # 原生+React实现懒加载(无限滚动)列表方式  # react无限滚动组件的实现示例  # React实现数字滚动组件numbers-scroll的示例详解  # React列表栏及购物车组件使用详解  # React Native中ScrollView组件轮播图与ListView渲染列表组件用法实例分析  # react实现列表滚动组件功能  # 自定义  # 说了  # 不多  # 还需要  # 美图  # 绑定  # 可以下载  # 而要  # 大家多多  # 选择了  # ii  # eachheight  # lt  # CURRENT_CITY_LIST  # length  # getRowData  # rowID  # log  # ds  # sectionIDs 


相关文章: 山东网站制作公司有哪些,山东大源集团官网?  如何快速搭建高效香港服务器网站?  郑州企业网站制作公司,郑州招聘网站有哪些?  如何获取免费开源的自助建站系统源码?  如何在Golang中使用replace替换模块_指定本地或远程路径  如何在万网开始建站?分步指南解析  常州自助建站工具推荐:低成本搭建与模板选择技巧  网页制作模板网站推荐,网页设计海报之类的素材哪里好?  在线ppt制作网站有哪些,请推荐几个好的课件下载的网站?  已有域名和空间,如何快速搭建网站?  威客平台建站流程解析:高效搭建教程与设计优化方案  如何在腾讯云服务器上快速搭建个人网站?  小米网站链接制作教程,请问miui新增网页链接调用服务有什么用啊?  建站一年半SEO优化实战指南:核心词挖掘与长尾流量提升策略  如何通过虚拟主机快速搭建个人网站?  义乌企业网站制作公司,请问义乌比较好的批发小商品的网站是什么?  深圳网站制作费用多少钱,读秀,深圳文献港这样的网站很多只提供网上试读,但有些人只要提供试读的文章就能全篇下载,这个是怎么弄的?  建站主机选哪种环境更利于SEO优化?  北京营销型网站制作公司,可以用python做一个营销推广网站吗?  网站设计制作公司地址,网站建设比较好的公司都有哪些?  建站10G流量真的够用吗?如何应对访问高峰?  小捣蛋自助建站系统:数据分析与安全设置双核驱动网站优化    如何配置支付宝与微信支付功能?  如何在万网主机上快速搭建网站?  XML的“混合内容”是什么 怎么用DTD或XSD定义  如何在云主机上快速搭建多站点网站?  c++怎么实现高并发下的无锁队列_c++ std::atomic原子变量与CAS操作【详解】  如何快速搭建高效服务器建站系统?  c# Task.ConfigureAwait(true) 在什么场景下是必须的  深入理解Android中的xmlns:tools属性  海南网站制作公司有哪些,海口网是哪家的?  ,制作一个手机app网站要多少钱?  电商网站制作多少钱一个,电子商务公司的网站制作费用计入什么科目?  seo网站制作优化,网站SEO优化步骤有哪些?  c# 在高并发场景下,委托和接口调用的性能对比  图片制作网站免费软件,有没有免费的网站或软件可以将图片批量转为A4大小的pdf?  免费的流程图制作网站有哪些,2025年教师初级职称申报网上流程?  如何挑选优质建站一级代理提升网站排名?  建站之星备案流程有哪些注意事项?  上海制作企业网站有哪些,上海有哪些网站可以让企业免费发布招聘信息?  C++ static_cast和dynamic_cast区别_C++静态转换与动态类型安全转换  惠州网站建设制作推广,惠州市华视达文化传媒有限公司怎么样?  如何在IIS中新建站点并配置端口与IP地址?  如何快速上传自定义模板至建站之星?  建站之星2.7模板快速切换与批量管理功能操作指南  建站之星安装提示数据库无法连接如何解决?  建站之星北京办公室:智能建站系统与小程序生成方案解析  如何高效生成建站之星成品网站源码?  PHP正则匹配日期和时间(时间戳转换)的实例代码 

您的项目需求

*请认真填写需求信息,我们会在24小时内与您取得联系。