欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2022-05-14 19:29:37
城市列表选择是很多app共有的功能,比如典型的美图app。那么对于react native怎么实现呢? 要实现上面的效果,首先需要对界面的组成简单分析,界面的数...

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

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

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