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 相关文章推荐
ASP 过滤数组重复数据函数(加强版)
May 31 Javascript
表单切换,用回车键替换Tab健(不支持IE)
Jul 20 Javascript
一张表格告诉你windows.onload()与$(document).ready()的区别
May 16 Javascript
js中document.write的那点事
Dec 12 Javascript
jQuery插件Validate实现自定义校验结果样式
Jan 18 Javascript
第二章之Bootstrap 页面排版样式
Apr 25 Javascript
bootstrap实现每隔5秒自动轮播效果
Dec 20 Javascript
JS判断非空至少输入两个字符的简单实现方法
Jun 23 Javascript
JavaScript实现树的遍历算法示例【广度优先与深度优先】
Oct 26 Javascript
js逆向解密之网络爬虫
May 30 Javascript
原理深度解析Vue的响应式更新比React快
Apr 04 Javascript
解决vuecli3中img src 的引入问题
Aug 04 Javascript
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
一个SQL管理员的web接口
2006/10/09 PHP
PHP中SimpleXML函数用法分析
2014/11/26 PHP
php+mysqli实现批量替换数据库表前缀的方法
2014/12/29 PHP
php str_getcsv把字符串解析为数组的实现方法
2017/04/05 PHP
ThinkPHP开发--使用七牛云储存
2017/09/14 PHP
php使用fputcsv实现大数据的导出操作详解
2020/02/27 PHP
js中substr,substring,indexOf,lastIndexOf的用法小结
2013/12/27 Javascript
js代码实现点击按钮出现60秒倒计时
2021/01/28 Javascript
JS及PHP代码编写八大排序算法
2016/07/12 Javascript
MUI 解决动态列表页图片懒加载再次加载不成功的bug问题
2017/04/13 Javascript
AngularJS中的promise用法分析
2017/05/19 Javascript
JavaScript设置名字输入不合法的实现方法
2017/05/23 Javascript
JS/HTML5游戏常用算法之碰撞检测 包围盒检测算法详解【凹多边形的分离轴检测算法】
2018/12/13 Javascript
Web安全之XSS攻击与防御小结
2018/12/13 Javascript
PHPStorm中如何对nodejs项目进行单元测试详解
2019/02/28 NodeJs
微信小程序开发注意指南和优化实践(小结)
2019/06/21 Javascript
详解jQuery中的prop()使用方法
2020/01/05 jQuery
Vue强制组件重新渲染的方法讨论
2020/02/03 Javascript
python中异常捕获方法详解
2017/03/03 Python
python解释器spython使用及原理解析
2019/08/24 Python
改变 Python 中线程执行顺序的方法
2020/09/24 Python
基于python模拟bfs和dfs代码实例
2020/11/19 Python
美国按摩椅批发网站:Titan Chair
2018/12/27 全球购物
俄罗斯茶和咖啡网上商店:Tea.ru
2021/01/26 全球购物
科室工作的个人自我评价
2013/10/30 职场文书
服务员岗位职责
2014/01/29 职场文书
机关作风整顿个人整改措施2014
2014/09/17 职场文书
幼儿教师师德师风自我剖析材料
2014/09/29 职场文书
学校师德师风自我剖析材料
2014/09/29 职场文书
商业用房租赁协议书
2014/10/13 职场文书
实习证明格式范文
2014/10/14 职场文书
高考百日冲刺决心书
2015/09/23 职场文书
祝福语集锦:朋友新店开业祝福语
2019/12/10 职场文书
教你用python控制安卓手机
2021/05/13 Python
关于MySQL中的 like操作符详情
2021/11/17 MySQL
MySQL约束(创建表时的各种条件说明)
2022/06/21 MySQL