短短的国庆8天假期一眨眼就过去了,下次长假只有等到过年了,本宝宝不开心。既然已经开始工作了,就要好好多学习点新知识,来提高自己的代码能力,今天带大家去实现简易的选择城市界面,并且可以根据城市首字母或者拼音搜索。先来看下我的效果图:

在写代码之前先准备好一个城市列表的json文件以及去百度或者高德申请定位功能,Demo在文章最后。(Demo里没有写定位功能,需要自己实现哦~)

实现方法也比较简单,我就简单的给大家说一下,整个城市列表是用的一个ListView,方便我们后面监听它的滚动状态,右边的快速定位栏是自定义View,代码比较简单,我就直接放代码了。不知道大家发现没有,有些字母开头的城市是没有的,比如 I,O,U,V等等,为了节约空间我就把那几个字母去掉了,有的软件是把26个字母全部保留了。

(其实都不影响,看你个人吧,我反正是有强迫症的。)注意,在自定义View的时候三种构造方法都要写上,千万不要偷懒!!!哎,都是泪  o(╥﹏╥)o

public class LetterListView extends View {OnTouchingLetterChangedListener onTouchingLetterChangedListener;public static String[] b = {"定位", "热门", "A", "B", "C", "D", "E", "F", "G", "H", "J", "K","L", "M", "N", "P", "Q", "R", "S", "T", "W", "X", "Y", "Z"};int choose = -1;Paint paint = new Paint();boolean showBkg = false;private Context mContext;public LetterListView(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);init(context);}public LetterListView(Context context, AttributeSet attrs) {super(context, attrs);init(context);}public LetterListView(Context context) {super(context);init(context);}private void init(Context context){this.mContext = context;paint.setColor(Color.parseColor("#50B3DA"));paint.setTextSize(DisplayUtil.sp2px(mContext, 12));paint.setAntiAlias(true);}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);if (showBkg) {canvas.drawColor(Color.parseColor("#40000000"));}int height = getHeight();int width = getWidth();int singleHeight = height / b.length;for (int i = 0; i < b.length; i++) {float xPos = width / 2 - paint.measureText(b[i]) / 2;float yPos = singleHeight * i + singleHeight;canvas.drawText(b[i], xPos, yPos, paint);}}@Overridepublic boolean dispatchTouchEvent(MotionEvent event) {final int action = event.getAction();final float y = event.getY();final int oldChoose = choose;final OnTouchingLetterChangedListener listener = onTouchingLetterChangedListener;final int c = (int) (y / getHeight() * b.length);switch (action) {case MotionEvent.ACTION_DOWN:showBkg = true;if (oldChoose != c && listener != null) {if (c >= 0 && c < b.length) {listener.onTouchingLetterChanged(b[c]);choose = c;invalidate();}}break;case MotionEvent.ACTION_MOVE:if (oldChoose != c && listener != null) {if (c >= 0 && c < b.length) {listener.onTouchingLetterChanged(b[c]);choose = c;invalidate();}}break;case MotionEvent.ACTION_UP:showBkg = false;choose = -1;invalidate();break;}return true;}@Overridepublic boolean onTouchEvent(MotionEvent event) {return super.onTouchEvent(event);}public void setOnTouchingLetterChangedListener(OnTouchingLetterChangedListener onTouchingLetterChangedListener) {this.onTouchingLetterChangedListener = onTouchingLetterChangedListener;}public interface OnTouchingLetterChangedListener {void onTouchingLetterChanged(String s);}}

使用的时候设置好宽度和高度:

<com.kairui.kyb.ui.view.widget.LetterListViewandroid:id="@+id/total_city_letters_lv"android:layout_width="25dp"android:layout_height="match_parent"android:layout_alignParentRight="true"android:layout_marginRight="2dp"android:layout_marginTop="7dp"android:layout_marginBottom="7dp"/>

接下来就是关键的地方了,咳咳~

一、 既然左边用到了ListView,那就少不了适配器和城市模型。

①、城市模型:其中拼音和首字母是方便用户搜索的时候进行筛选,CityCode你们可以不用去管,我主要是用来请求数据。

public class CityEntity {private String name;private String key;private String pinyin;  //全拼private String first;   //首字母private String cityCode;public String getName() {return name;}public void setName(String name) {this.name = name;}public String getKey() {return key;}public void setKey(String key) {this.key = key;}public String getPinyin() {return pinyin;}public void setPinyin(String pinyin) {this.pinyin = pinyin;}public String getFirst() {return first;}public void setFirst(String first) {this.first = first;}public String getCityCode() {return cityCode;}public void setCityCode(String cityCode) {this.cityCode = cityCode;}
}

②、全部城市列表的适配器:我这里将全部城市列表分成了三种类型,第一种就是当前定位城市的布局,第二种就是热门城市的布局,(当然了,热门城市你们可以从后台获取,我图方便就写死在本地了),第三种就是全部城市的布局了

/*** 总城市适配器*/private class CityListAdapter extends BaseAdapter {private Context context;private List<CityEntity> totalCityList;private List<CityEntity> hotCityList;private LayoutInflater inflater;final int VIEW_TYPE = 3;CityListAdapter(Context context,List<CityEntity> totalCityList,List<CityEntity> hotCityList) {this.context = context;this.totalCityList = totalCityList;this.hotCityList = hotCityList;inflater = LayoutInflater.from(context);alphaIndexer = new HashMap<>();for (int i = 0; i < totalCityList.size(); i++) {// 当前汉语拼音首字母String currentStr = totalCityList.get(i).getKey();String previewStr = (i - 1) >= 0 ? totalCityList.get(i - 1).getKey() : " ";if (!previewStr.equals(currentStr)) {String name = getAlpha(currentStr);alphaIndexer.put(name, i);}}}@Overridepublic int getViewTypeCount() {return VIEW_TYPE;}@Overridepublic int getItemViewType(int position) {return position < 2 ? position : 2;}@Overridepublic int getCount() {return totalCityList == null ? 0 : totalCityList.size();}@Overridepublic Object getItem(int position) {return totalCityList.get(position);}@Overridepublic long getItemId(int position) {return position;}@Overridepublic View getView(int position, View convertView, ViewGroup parent) {final TextView curCityNameTv;ViewHolder holder;int viewType = getItemViewType(position);if (viewType == 0) { // 定位convertView = inflater.inflate(R.layout.select_city_location_item, null);LinearLayout noLocationLl = (LinearLayout) convertView.findViewById(R.id.cur_city_no_data_ll);TextView getLocationTv = (TextView) convertView.findViewById(R.id.cur_city_re_get_location_tv);curCityNameTv = (TextView) convertView.findViewById(R.id.cur_city_name_tv);if (TextUtils.isEmpty(locationCity)) {noLocationLl.setVisibility(View.VISIBLE);curCityNameTv.setVisibility(View.GONE);getLocationTv.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {initLocation();}});} else {noLocationLl.setVisibility(View.GONE);curCityNameTv.setVisibility(View.VISIBLE);curCityNameTv.setText(locationCity);curCityNameTv.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {if (!locationCity.equals(UserConstant.curSelCity)) {//设置城市代码String cityCode = "";for (CityEntity cityEntity : AppCache.getInstance().getCurCityList()) {if (cityEntity.getName().equals(locationCity)) {cityCode = cityEntity.getCityCode();break;}}showSetCityDialog(locationCity, cityCode);} else {ToastUtils.show("当前定位城市" + curCityNameTv.getText().toString());}}});}} else if (viewType == 1) { //热门城市convertView = inflater.inflate(R.layout.recent_city_item, null);GridView hotCityGv = (GridView) convertView.findViewById(R.id.recent_city_gv);hotCityGv.setAdapter(new HotCityListAdapter(context, this.hotCityList));hotCityGv.setOnItemClickListener(new AdapterView.OnItemClickListener() {@Overridepublic void onItemClick(AdapterView<?> parent, View view,int position, long id) {CityEntity cityEntity = hotCityList.get(position);showSetCityDialog(cityEntity.getName(), cityEntity.getCityCode());}});} else {if (null == convertView) {holder = new ViewHolder();convertView = inflater.inflate(R.layout.city_list_item_layout, null);ViewBinder.bind(holder, convertView);convertView.setTag(holder);} else {holder = (ViewHolder) convertView.getTag();}CityEntity cityEntity = totalCityList.get(position);holder.cityKeyTv.setVisibility(View.VISIBLE);holder.cityKeyTv.setText(getAlpha(cityEntity.getKey()));holder.cityNameTv.setText(cityEntity.getName());if (position >= 1) {CityEntity preCity = totalCityList.get(position - 1);if (preCity.getKey().equals(cityEntity.getKey())) {holder.cityKeyTv.setVisibility(View.GONE);} else {holder.cityKeyTv.setVisibility(View.VISIBLE);}}}return convertView;}private class ViewHolder {@Bind(R.id.city_name_tv)TextView cityNameTv;@Bind(R.id.city_key_tv)TextView cityKeyTv;}}

1)、当前定位城市布局:定位失败的话显示出来,并且提示用户去开启GPS

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="wrap_content"android:background="@color/white"android:orientation="vertical"><TextViewandroid:id="@+id/city_item_hint_tv"android:layout_width="match_parent"android:layout_height="25dp"android:background="@color/mainGray"android:gravity="center_vertical"android:paddingLeft="20dp"android:paddingRight="20dp"android:drawablePadding="5dp"android:drawableLeft="@drawable/ic_location"android:text="当前定位城市"android:textColor="@color/gray_9"android:textSize="14sp" /><TextViewandroid:id="@+id/cur_city_name_tv"android:layout_width="90dp"android:layout_height="wrap_content"android:layout_marginBottom="10dp"android:layout_marginLeft="20dp"android:layout_marginRight="20dp"android:layout_marginTop="10dp"android:background="@drawable/shape_gray_border_pres_style"android:ellipsize="end"android:gravity="center"android:textColor="@color/mainColor"android:textSize="14sp"android:visibility="gone" /><LinearLayoutandroid:id="@+id/cur_city_no_data_ll"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginBottom="5dp"android:layout_marginTop="5dp"android:orientation="horizontal"><TextViewandroid:layout_width="0dp"android:layout_height="wrap_content"android:layout_marginLeft="20dp"android:layout_weight="1"android:text="无法获取您的定位地址" /><TextViewandroid:id="@+id/cur_city_re_get_location_tv"android:layout_width="120dp"android:layout_height="35dp"android:layout_marginLeft="30dp"android:layout_marginRight="30dp"android:background="@drawable/round_btn_pres_style"android:gravity="center"android:text="重新获取"android:textColor="@color/white" /></LinearLayout>
</LinearLayout>

2)、热门城市布局:记住,这里直接使用GridView的话只会显示一行数据,需要继承GridView并重写OnMeasure方法,网上有很多案例,就不放代码了。

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="wrap_content"android:background="@color/white"android:orientation="vertical"><TextViewandroid:layout_width="match_parent"android:layout_height="25dp"android:background="@color/mainGray"android:drawableLeft="@drawable/ic_hot"android:drawablePadding="5dp"android:gravity="center_vertical"android:paddingLeft="20dp"android:paddingRight="20dp"android:text="热门城市"android:textColor="@color/gray_9"/><com.kairui.kyb.ui.view.widget.ScrollWithGridViewandroid:id="@+id/recent_city_gv"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginBottom="10dp"android:layout_marginLeft="20dp"android:layout_marginRight="30dp"android:layout_marginTop="10dp"android:horizontalSpacing="10dp"android:listSelector="@android:color/transparent"android:numColumns="3"android:verticalSpacing="10dp" /></LinearLayout>

3)、全部城市的单行布局:每绘制一条数据判断前一个数据的Key是否与现在的相同,true则不显示  city_key_tv,保证同一个Key的城市只有一个显示。

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="wrap_content"android:background="@drawable/recycler_bg"android:orientation="vertical"><TextViewandroid:id="@+id/city_key_tv"android:layout_width="match_parent"android:layout_height="25dp"android:background="@color/mainGray"android:gravity="center_vertical"android:paddingLeft="32dp"android:paddingRight="32dp"android:textColor="@color/gray_9"android:textSize="14sp" /><TextViewandroid:id="@+id/city_name_tv"android:layout_width="match_parent"android:layout_height="45dp"android:gravity="center_vertical"android:paddingLeft="20dp"android:paddingRight="20dp"android:textColor="@color/gray_6"android:textSize="15sp" /><Viewstyle="@style/default_line"android:layout_marginLeft="@dimen/common_20"android:layout_marginRight="@dimen/common_20" /></LinearLayout>

③、热门城市列表适配器:比较简单,不过多说明。

 /*** 热门城市适配器*/private class HotCityListAdapter extends BaseAdapter {private List<CityEntity> cityEntities;private LayoutInflater inflater;HotCityListAdapter(Context mContext, List<CityEntity> cityEntities) {this.cityEntities = cityEntities;inflater = LayoutInflater.from(mContext);}@Overridepublic int getCount() {return cityEntities == null ? 0 : cityEntities.size();}@Overridepublic Object getItem(int position) {return cityEntities.get(position);}@Overridepublic long getItemId(int position) {return position;}@Overridepublic View getView(int position, View convertView, ViewGroup parent) {ViewHolder holder;if (null == convertView) {holder = new ViewHolder();convertView = inflater.inflate(R.layout.city_list_grid_item_layout, null);ViewBinder.bind(holder, convertView);convertView.setTag(holder);} else {holder = (ViewHolder) convertView.getTag();}CityEntity cityEntity = cityEntities.get(position);holder.cityNameTv.setText(cityEntity.getName());return convertView;}private class ViewHolder {@Bind(R.id.city_list_grid_item_name_tv)TextView cityNameTv;}}

二、初始化首字母提示框,并且设置ListVIew的滚动监听以及自定义View的Touch事件

    /*** 初始化汉语拼音首字母弹出提示框*/private void initOverlay() {mReady = true;LayoutInflater inflater = LayoutInflater.from(this);overlay = (TextView) inflater.inflate(R.layout.overlay, null);overlay.setVisibility(View.INVISIBLE);WindowManager.LayoutParams lp = new WindowManager.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT,WindowManager.LayoutParams.TYPE_APPLICATION,WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,PixelFormat.TRANSLUCENT);WindowManager windowManager = (WindowManager) this.getSystemService(Context.WINDOW_SERVICE);windowManager.addView(overlay, lp);}
private class LetterListViewListener implementsLetterListView.OnTouchingLetterChangedListener {@Overridepublic void onTouchingLetterChanged(final String s) {isScroll = false;if (alphaIndexer.get(s) != null) {int position = alphaIndexer.get(s);totalCityLv.setSelection(position);overlay.setText(s);overlay.setVisibility(View.VISIBLE);handler.removeCallbacks(overlayThread);// 延迟让overlay为不可见handler.postDelayed(overlayThread, 700);}}}/*** 设置overlay不可见*/private class OverlayThread implements Runnable {@Overridepublic void run() {overlay.setVisibility(View.GONE);}}@Overridepublic void onScrollStateChanged(AbsListView view, int scrollState) {if (scrollState == SCROLL_STATE_TOUCH_SCROLL|| scrollState == SCROLL_STATE_FLING) {isScroll = true;} else {isScroll = false;}}@Overridepublic void onScroll(AbsListView view, int firstVisibleItem,int visibleItemCount, int totalItemCount) {if (!isScroll) {return;}if (mReady) {String key = getAlpha(totalCityList.get(firstVisibleItem).getKey());overlay.setText(key);overlay.setVisibility(View.VISIBLE);handler.removeCallbacks(overlayThread);// 延迟让overlay为不可见handler.postDelayed(overlayThread, 700);}}

其中最主要关键的地方就是以上这些了

最后我就放上demo的下载地址了,Demo点我

就是这些了,祝大家第一天工作愉快~

-------------------------------

2019-10-09更新

CSDN当初上传设置的最低1分,现在居然涨到50了,,,过分。现在传到了百度云,  提取码:l7ip

欢迎自取,好用的话,不放点个关注。谢谢~~

Android开发实现选择城市界面,可根据拼音、首字母进行搜索相关推荐

  1. Android上实现一个简单的天气预报APP(七) 切换到新的界面(选择城市界面)

    学习参考资源:https://www.gitbook.com/book/zhangqx/mini-weather/details 前面我们已经设置好了基本界面,并可以从网络上实时获取天气预报信息并解析 ...

  2. 【Android】快速实现仿美团选择城市界面,微信通讯录界面

    概述 本文是这个系列的第三篇,不出意外也是终结篇.因为使用经过重构后的控件已经可以快速实现市面上带 索引导航.悬停分组的列表界面了. 在前两篇里,我们从0开始,一步一步实现了仿微信通讯录.饿了么选餐界 ...

  3. Android 仿美团选择城市、微信通讯录、饿了么点餐列表的导航悬停分组索引列表

    SuspensionIndexBar 项目地址:mcxtzhang/SuspensionIndexBar 简介:快速实现分组悬停.右侧索引导航联动 列表. 如 美团选择城市界面,微信通讯录界面.饿了么 ...

  4. [Android] Android开发优化之——对界面UI的优化(2)

    在Android应用开发过程中,屏幕上控件的布局代码和程序的逻辑代码通常是分开的.界面的布局代码是放在一个独立的xml文件中的,这个文件里面是树型组织的,控制着页面的布局.通常,在这个页面中会用到很多 ...

  5. Android开发本地及网络Mp3音乐播放器(十三)网络音乐搜索功能实现,歌名歌手专辑名搜索

    转载请注明出处:http://blog.csdn.net/iwanghang/article/details/51298411 觉得博文有用,请点赞,请留言,请关注,谢谢!~ 实现功能: 实现网络音乐 ...

  6. 城市列表-根据拼音首字母排序

    今天我们就简单的实现一下城市的排序 读取我们城市的信息并通过listview展示 首先看一下我们的布局文件 <LinearLayout xmlns:android="http://sc ...

  7. 全国省市区数据库-拼音-首字母-经纬度-城市编码-邮编-简称-组合称

    全国省市区数据库-拼音-首字母-经纬度-城市编码-邮编-简称-组合称 全国省市区数据库-拼音-首字母-经纬度-城市编码-邮编-简称-组合称 MySql转储文件,Excel数据文档 全国省市区数据库-拼 ...

  8. 姓名拼音首字母缩写_企业开发人员,首字母缩写词和歧视

    姓名拼音首字母缩写 在过去的几年中,我的客户从大多数中型市场公司和一些初创公司转变为几乎完全是初创公司,这种转变导致客户要求的语言范围更加广泛. 在我职业生涯的前10年中,我的业务约占Java的95% ...

  9. Android 利用AutoCompleteTextView实现模糊搜索功能,搜索结果自动提示,识别拼音首字母并转汉字提示

    这里说一下怎么利用 Android 的 AutoCompleteTextView 控件实现模糊搜索功能,AutoCompleteTextView 自带自动提示功能.如果 对自动提示的布局自定义要求比较 ...

  10. Android仿美团选择城市

    需求:需要有当前定位城市,热门城市,下面按照城市首拼音排序,滑动的过程中字母A,B,C-会置顶互相切换.右侧有快速切换字母城市的选择 效果图: 思路:因为上部分要划走,RecyclerView滑动过程 ...

最新文章

  1. About The FTP
  2. Android 简单天气预报
  3. Django的APP,视图,url和模板
  4. 学习进度条(第十五周)
  5. miniui页面移动的时候透明_【H5】316 移动端H5跳坑指南
  6. 【JavaScript代码实现四】获取和设置 cookie
  7. mysql多列 groupby,MySQL多表查询之GroupBy
  8. win10清理_无需第三方,win10也可以实现自动清理垃圾
  9. git stash后怎么恢复_苹果换卡后怎么恢复通讯录?两种方法帮你解决
  10. #1062 – Duplicate entry ‘1’ for key ‘PRIMARY’
  11. 第六届蓝桥杯java b组第一题
  12. java集合框架小结
  13. 计算机提示无法验证发布者,win10 ie11提示由于无法验证发布者所以windows已经阻止此软件怎么办...
  14. 期刊论文添加基金项目、作者简介
  15. Win7系统交互式服务检测关闭方法-
  16. 1.1 C++小游戏——创造世界
  17. 大数据在各个行业中的具体作用
  18. static关键字和块和包机制和继承super
  19. [干货分享]数美联合创始人CTO梁堃: 无孔不入的机器学习与人工智能
  20. python图形用户界面编程

热门文章

  1. 计算机显存影响什么,老司机告诉你显存是怎样影响电脑速度的
  2. java随机答题器_Advanced Random Auto Clicker免费版下载-多合一随机自动答题器 v4.21 免费版 - 安下载...
  3. 200行Python实现的qq连连看辅助,用于学习,请不要拿去伤害玩家
  4. 超市网店营销与接口测试
  5. IIS提示您未被授权查看该页 401.1解决办法
  6. SU2 CFD代码阅读
  7. 为何大多数人还在学Java 目前Java好就业吗
  8. 数据库开发技术的课程记录
  9. 母亲节为什么要定在5月的第二个星期日? [节假日]
  10. Python 基于 uiautomator2 实现《全民开喵铺》自动收币,自动签到,自动浏览得喵币