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


Posted in Javascript onAugust 08, 2017

城市列表选择是很多app共有的功能,比如典型的美图app。那么对于React Native怎么实现呢?

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带索引的城市列表组件的实例代码 

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

最后是界面的绘制,这里就不多说了,大家可以下载源码自行查看。源码地址:react-native-city_3water.rar

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

Javascript 相关文章推荐
Js之软键盘实现(js源码)
Jan 30 Javascript
js 实现日期灵活格式化的小例子
Jul 14 Javascript
清除div下面的所有标签的方法
Feb 17 Javascript
JavaScript设计模式之建造者模式介绍
Dec 28 Javascript
JS实现页面超时后自动跳转到登陆页面
Jan 19 Javascript
Jquery为DIV添加click事件的简单实例
Jun 02 Javascript
jQuery判断是否存在滚动条的简单方法
Sep 17 Javascript
AngularJS用户选择器指令实例分析
Nov 04 Javascript
获取JavaScript异步函数的返回值
Dec 21 Javascript
vue element-ui实现动态面包屑导航
Dec 23 Javascript
三步搞定:Vue.js调用Android原生操作
Sep 07 Javascript
springboot+vue实现文件上传下载
Nov 17 Vue.js
React Native仿美团下拉菜单的实例代码
Aug 08 #Javascript
React-Native 组件之 Modal的使用详解
Aug 08 #Javascript
基于jQuery对象和DOM对象和字符串之间的转化实例
Aug 08 #jQuery
超级简易的JS计算器实例讲解(实现加减乘除)
Aug 08 #Javascript
浅谈ES6新增的数组方法和对象
Aug 08 #Javascript
Angularjs上传文件组件flowjs功能
Aug 07 #Javascript
详解Vue的computed(计算属性)使用实例之TodoList
Aug 07 #Javascript
You might like
JAVA/JSP学习系列之二
2006/10/09 PHP
php设计模式之单例、多例设计模式的应用分析
2013/06/30 PHP
PHP中strtr字符串替换用法详解
2014/11/26 PHP
PHP实现生成唯一会员卡号
2015/08/24 PHP
PHP简单实现正则匹配省市区的方法
2018/04/13 PHP
PHP实现会员账号单唯一登录的方法分析
2019/03/07 PHP
laravel 使用事件系统统计浏览量的实现
2019/10/16 PHP
PHP设计模式(三)建造者模式Builder实例详解【创建型】
2020/05/02 PHP
Zero Clipboard js+swf实现的复制功能使用方法
2010/03/07 Javascript
Jquery显示和隐藏元素或设为只读(含Ligerui的控件禁用,实例说明介绍)
2013/07/09 Javascript
让input框实现类似百度的搜索提示(基于jquery事件监听)
2014/01/31 Javascript
jquery中子元素和后代元素的区别示例介绍
2014/04/02 Javascript
javascript如何使用bind指定接收者
2014/05/04 Javascript
TypeScript具有的几个不同特质
2015/04/07 Javascript
js改变Iframe中Src的方法
2015/05/05 Javascript
如何重置vue打印变量的显示方式
2017/12/06 Javascript
JavaScrip关于创建常量的知识点
2017/12/07 Javascript
vscode中vue-cli项目es-lint的配置方法
2018/07/30 Javascript
浅谈如何优雅处理JavaScript异步错误
2019/11/12 Javascript
ES6 Object.assign()的用法及其使用
2020/01/18 Javascript
[03:27]最受玩家喜爱奖提名:PZH_Element 致玩家寄语
2016/12/20 DOTA
python迭代器的使用方法实例
2013/11/21 Python
python3 遍历删除特定后缀名文件的方法
2018/04/23 Python
通过python检测字符串的字母
2020/02/18 Python
Selenium启动Chrome时配置选项详解
2020/03/18 Python
使用Python和百度语音识别生成视频字幕的实现
2020/04/09 Python
基于python实现对文件进行切分行
2020/04/26 Python
Python+kivy BoxLayout布局示例代码详解
2020/12/28 Python
Grow Gorgeous美国官网:只要八天,体验唤醒毛囊后新生的茂密秀发
2018/06/04 全球购物
幼儿师范毕业生自荐信
2013/11/09 职场文书
少先队学雷锋活动月总结
2014/03/09 职场文书
电气工程自动化求职信
2014/03/14 职场文书
战友聚会策划方案
2014/06/13 职场文书
孙振耀退休感言
2015/08/01 职场文书
Windows Server 2016 配置 IIS 的详细步骤
2022/04/28 Servers