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 Loading功能的简单实现
Nov 29 Javascript
JavaScript中诡异的delete操作符
Mar 12 Javascript
JS+CSS实现大气清新的滑动菜单效果代码
Oct 22 Javascript
AngularJS控制器之间的数据共享及通信详解
Aug 01 Javascript
js实现贪吃蛇小游戏(容易理解)
Jan 22 Javascript
JS对象是否拥有某属性如何判断
Feb 03 Javascript
jQuery实现鼠标经过显示动画边框特效
Mar 24 jQuery
微信小程序页面生命周期详解
Jan 31 Javascript
jQuery实现左右滑动的toggle方法
Mar 03 jQuery
详解vue axios二次封装
Jul 22 Javascript
js代码规范之Eslint安装与配置详解
Sep 08 Javascript
JQuery获取元素尺寸、位置及页面滚动事件应用示例
May 14 jQuery
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
PHP 选项及相关信息函数库
2006/12/04 PHP
一组PHP加密解密函数分享
2014/06/05 PHP
简单谈谈php中的unicode和utf8编码
2015/06/10 PHP
Zend Framework实现多文件上传功能实例
2016/03/21 PHP
静态html文件执行php语句的方法(推荐)
2016/11/21 PHP
Laravel 验证码认证学习记录小结
2019/12/20 PHP
仅用[]()+!等符号就足以实现几乎任意Javascript代码
2010/03/01 Javascript
基于JQuery的一句代码实现表格的简单筛选
2010/07/26 Javascript
jquery mobile事件多次绑定示例代码
2013/09/13 Javascript
js跑步算法的实现代码
2013/12/04 Javascript
jquery事件重复绑定的快速解决方法
2014/01/03 Javascript
抛弃Nginx使用nodejs做反向代理服务器
2014/07/17 NodeJs
$(&quot;&quot;).click与onclick的区别示例介绍
2014/09/25 Javascript
node.js中的socket.io的广播消息
2014/12/15 Javascript
JQuery球队选择实例
2015/05/18 Javascript
jquery编写Tab选项卡滚动导航切换特效
2020/07/17 Javascript
AngularJS 所有版本下载地址
2016/09/14 Javascript
微信小程序 生命周期函数详解
2017/05/24 Javascript
three.js实现3D影院的原理的代码分析
2017/12/18 Javascript
pace.js和NProgress.js两个加载进度插件的一点小总结
2018/01/31 Javascript
create-react-app 修改为多入口编译的方法
2018/08/01 Javascript
Vue实现返回顶部按钮实例代码
2020/10/21 Javascript
[39:07]LGD vs VP 2018国际邀请赛淘汰赛BO3 第二场 8.21
2018/08/22 DOTA
Python中使用摄像头实现简单的延时摄影技术
2015/03/27 Python
Python的装饰器模式与面向切面编程详解
2015/06/21 Python
修复CentOS7升级Python到3.6版本后yum不能正确使用的解决方法
2018/01/26 Python
python计算两个地址之间的距离方法
2018/06/09 Python
django settings.py 配置文件及介绍
2019/07/15 Python
基于python修改srt字幕的时间轴
2020/02/03 Python
一篇文章搞懂python的转义字符及用法
2020/09/03 Python
基于Python实现粒子滤波效果
2020/12/01 Python
小学教师的个人自我鉴定
2013/10/24 职场文书
日语系毕业求职信
2014/07/27 职场文书
干部作风建设心得体会
2014/10/22 职场文书
2014年乡镇人大工作总结
2014/11/25 职场文书
CSS实现渐变色边框(Gradient borders)的5种方法
2022/03/25 HTML / CSS