Android实战简易教程-第六十枪(分享一个城市选择功能模块)

在做一些APP的时候可能会用到城市选择模块的功能,本实例可以提供位置自定定位和手动选择的功能,非常好用,大家可以修改后加入自己的项目中。

首先看一下效果:

1.进入有的手机可能会提示权限要求,这时我们选择允许。

2.选择允许后进入:

这个位置可以看到我们的城市已经通过GPS获取到了

点击这个控件,城市获取完成了:

下面我们看一下关键代码如何实现这个功能效果。

1.MainActivity.java:

package com.winxiang.locationselect;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;

public class MainActivity extends Activity {
	private TextView city_name;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		city_name = (TextView) findViewById(R.id.city_name);
	}

	public void goSelcet(View v){
		startActivityForResult(new Intent(MainActivity.this,ActivitySelectCity.class), 99);
	}
	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		// TODO Auto-generated method stub
		try{
			switch (resultCode) {
			case 99:
				city_name.setText(data.getStringExtra("lngCityName"));
				break;

			default:
				break;
			}
		}catch (Exception e) {
			e.printStackTrace();
		}
		super.onActivityResult(requestCode, resultCode, data);
	}
}

很是简单,有一个跳转按钮。

2.ActivitySelectCity.java:

package com.winxiang.locationselect;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.regex.Pattern;

import org.json.JSONArray;
import org.json.JSONObject;

import com.baidu.location.BDLocation;
import com.baidu.location.BDLocationListener;
import com.baidu.location.LocationClient;
import com.baidu.location.LocationClientOption;

import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.graphics.PixelFormat;
import android.os.Bundle;
import android.os.Handler;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.BaseAdapter;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;

import com.winxiang.locationselect.MyLetterListView.OnTouchingLetterChangedListener;

public class ActivitySelectCity extends Activity{
	private ListAdapter adapter;
	private ListView personList;
	private ImageView imgback;
	private TextView overlay; // 对话框首字母textview
	private MyLetterListView letterListView; // A-Z listview
	private HashMap<String, Integer> alphaIndexer;// 存放存在的汉语拼音首字母和与之对应的列表位置
	private String[] sections;// 存放存在的汉语拼音首字母
	private Handler handler;
	private OverlayThread overlayThread; // 显示首字母对话框
	private ArrayList<City> allCity_lists; // 所有城市列表
	private ArrayList<City> ShowCity_lists; // 需要显示的城市列表-随搜索而改变
	private ArrayList<City> city_lists;// 城市列表
	private String lngCityName ="";//存放返回的城市名
	private JSONArray chineseCities ;
	private LocationClient locationClient = null;
	private EditText sh;
	private TextView lng_city;
	private LinearLayout lng_city_lay;
	private ProgressDialog progress;
	private static final int SHOWDIALOG = 2;
	private static final int DISMISSDIALOG = 3;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_selectcity);
		personList = (ListView) findViewById(R.id.list_view);
		allCity_lists = new ArrayList<City>();
		letterListView = (MyLetterListView) findViewById(R.id.MyLetterListView01);
		lng_city_lay = (LinearLayout) findViewById(R.id.lng_city_lay);
		sh = (EditText) findViewById(R.id.sh);
		lng_city = (TextView) findViewById(R.id.lng_city);
		imgback = (ImageView) findViewById(R.id.imgback);

		letterListView.setOnTouchingLetterChangedListener(new LetterListViewListener());
		alphaIndexer = new HashMap<String, Integer>();
		handler = new Handler();
		overlayThread = new OverlayThread();
		personList.setOnItemClickListener(new OnItemClickListener() {
			@Override
			public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
					long arg3) {
				Intent intent = new Intent();
				intent.putExtra("lngCityName", ShowCity_lists.get(arg2).name);
				setResult(99,intent);
				finish();
			}
		});
		lng_city_lay.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				Intent intent = new Intent();
				intent.putExtra("lngCityName",lngCityName);
				setResult(99,intent);
				finish();
			}
		});
		imgback.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				finish();
			}
		});

		initGps();
		initOverlay();
		handler2.sendEmptyMessage(SHOWDIALOG);
		Thread thread = new Thread(){
			@Override
			public void run() {
				hotCityInit();
				handler2.sendEmptyMessage(DISMISSDIALOG);
				super.run();
			}
		};
		thread.start();
	}

	/**
	 * 热门城市
	 */
	public void hotCityInit() {
		City city;
		city = new City("上海", "");
		allCity_lists.add(city);
		city = new City("北京", "");
		allCity_lists.add(city);
		city = new City("广州", "");
		allCity_lists.add(city);
		city = new City("深圳", "");
		allCity_lists.add(city);
		city = new City("武汉", "");
		allCity_lists.add(city);
		city = new City("天津", "");
		allCity_lists.add(city);
		city = new City("西安", "");
		allCity_lists.add(city);
		city = new City("南京", "");
		allCity_lists.add(city);
		city = new City("杭州", "");
		allCity_lists.add(city);
		city = new City("成都", "");
		allCity_lists.add(city);
		city = new City("重庆", "");
		allCity_lists.add(city);
		city_lists = getCityList();
		allCity_lists.addAll(city_lists);
		ShowCity_lists=allCity_lists;
	}

	/**
	 *
	 * 通过json数据获取城市列表
	 * @author yayun
	 * @since 2015年9月18日
	 *@return
	 */
	private ArrayList<City> getCityList() {
		ArrayList<City> list = new ArrayList<City>();
		try {
			chineseCities = new JSONArray(getResources().getString(R.string.citys));
			for(int i=0;i<chineseCities.length();i++){
				JSONObject jsonObject = chineseCities.getJSONObject(i);
				City city = new City(jsonObject.getString("name"), jsonObject.getString("pinyin"));
				list.add(city);
			}

		} catch (Exception e) {
			e.printStackTrace();
		}
		Collections.sort(list, comparator);
		return list;
	}

	/**
	 * a-z排序
	 */
	Comparator comparator = new Comparator<City>() {
		@Override
		public int compare(City lhs, City rhs) {
			String a = lhs.getPinyi().substring(0, 1);
			String b = rhs.getPinyi().substring(0, 1);
			int flag = a.compareTo(b);
			if (flag == 0) {
				return a.compareTo(b);
			} else {
				return flag;
			}

		}
	};

	/**
	 * ListView的adapter
	 * @author yayun
	 * @since 2015年9月18日
	 *
	 */
	public class ListAdapter extends BaseAdapter {
		private LayoutInflater inflater;
		final int VIEW_TYPE = 3;

		public ListAdapter(Context context) {
			this.inflater = LayoutInflater.from(context);
			alphaIndexer = new HashMap<String, Integer>();
			sections = new String[ShowCity_lists.size()];
			for (int i = 0; i < ShowCity_lists.size(); i++) {
				// 当前汉语拼音首字母
				String currentStr = getAlpha(ShowCity_lists.get(i).getPinyi());
				// 上一个汉语拼音首字母,如果不存在为“ ”
				String previewStr = (i - 1) >= 0 ? getAlpha(ShowCity_lists.get(i - 1)
						.getPinyi()) : " ";
				if (!previewStr.equals(currentStr)) {
					String name = getAlpha(ShowCity_lists.get(i).getPinyi());
					alphaIndexer.put(name, i);
					sections[i] = name;
				}
			}
		}

		@Override
		public int getCount() {
			return ShowCity_lists.size();
		}

		@Override
		public Object getItem(int position) {
			return ShowCity_lists.get(position);
		}

		@Override
		public long getItemId(int position) {
			return position;
		}

		@Override
		public int getItemViewType(int position) {
			// TODO Auto-generated method stub
			int type = 2;

			if (position == 0&&sh.getText().length()==0) {//不是在搜索状态下
				type = 0;
			}
			return type;
		}

		@Override
		public int getViewTypeCount() {// 这里需要返回需要集中布局类型,总大小为类型的种数的下标
			return VIEW_TYPE;
		}

		@Override
		public View getView(int position, View convertView, ViewGroup parent) {
			ViewHolder holder;
			int viewType = getItemViewType(position);
				if (convertView == null) {
					convertView = inflater.inflate(R.layout.list_item, null);
					holder = new ViewHolder();
					holder.alpha = (TextView) convertView
							.findViewById(R.id.alpha);
					holder.name = (TextView) convertView
							.findViewById(R.id.name);
					convertView.setTag(holder);
				} else {
					holder = (ViewHolder) convertView.getTag();
				}
//				if (sh.getText().length()==0) {//搜所状态
//					holder.name.setText(list.get(position).getName());
//					holder.alpha.setVisibility(View.GONE);
//				}else if(position>0){
				//显示拼音和热门城市,一次检查本次拼音和上一个字的拼音,如果一样则不显示,如果不一样则显示

					holder.name.setText(ShowCity_lists.get(position).getName());
					String currentStr = getAlpha(ShowCity_lists.get(position).getPinyi());//本次拼音
					String previewStr = (position-1) >= 0 ? getAlpha(ShowCity_lists.get(position-1).getPinyi()) : " ";//上一个拼音
					if (!previewStr.equals(currentStr)) {//不一样则显示
						holder.alpha.setVisibility(View.VISIBLE);
						if (currentStr.equals("#")) {
							currentStr = "热门城市";
						}
						holder.alpha.setText(currentStr);
					} else {
						holder.alpha.setVisibility(View.GONE);
					}
//				}
			return convertView;
		}

		private class ViewHolder {
			TextView alpha; // 首字母标题
			TextView name; // 城市名字
		}
	}

	// 初始化汉语拼音首字母弹出提示框
	private void initOverlay() {
		LayoutInflater inflater = LayoutInflater.from(this);
		overlay = (TextView) inflater.inflate(R.layout.overlay, null);
		overlay.setVisibility(View.INVISIBLE);
		WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
				LayoutParams.WRAP_CONTENT, 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 implements
			OnTouchingLetterChangedListener {

		@Override
		public void onTouchingLetterChanged(final String s) {
			if (alphaIndexer.get(s) != null) {
				int position = alphaIndexer.get(s);
				personList.setSelection(position);
				overlay.setText(sections[position]);
				overlay.setVisibility(View.VISIBLE);
				handler.removeCallbacks(overlayThread);
				// 延迟一秒后执行,让overlay为不可见
				handler.postDelayed(overlayThread, 1500);
			}
		}

	}

	// 设置overlay不可见
	private class OverlayThread implements Runnable {
		@Override
		public void run() {
			overlay.setVisibility(View.GONE);
		}

	}

	// 获得汉语拼音首字母
	private String getAlpha(String str) {

		if (str.equals("-")) {
			return "&";
		}
		if (str == null) {
			return "#";
		}
		if (str.trim().length() == 0) {
			return "#";
		}
		char c = str.trim().substring(0, 1).charAt(0);
		// 正则表达式,判断首字母是否是英文字母
		Pattern pattern = Pattern.compile("^[A-Za-z]+$");
		if (pattern.matcher(c + "").matches()) {
			return (c + "").toUpperCase();
		} else {
			return "#";
		}
	}

	/**
	 *
	 * 初始化GPS
	 * @author yayun
	 * @since 2015年9月18日
	 */
	private void initGps() {
		try{
			MyLocationListenner myListener = new MyLocationListenner();
			locationClient = new LocationClient(ActivitySelectCity.this);
			locationClient.registerLocationListener(myListener);
			LocationClientOption option = new LocationClientOption();
			option.setOpenGps(true);
			option.setAddrType("all");
			option.setCoorType("bd09ll");
			option.setScanSpan(5000);
			option.disableCache(true);
			option.setPoiNumber(5);
			option.setPoiDistance(1000);
			option.setPoiExtraInfo(true);
			option.setPriority(LocationClientOption.GpsFirst);
			locationClient.setLocOption(option);
			locationClient.start();
		}catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 销毁
	 */
	@Override
	public void onDestroy() {
		super.onDestroy();
		locationClient.stop();
	}

	/**
	 * 通过位置SDK获取现在所在城市
	 * @author yayun
	 * @since 2015年9月18日
	 *
	 */

	private class MyLocationListenner implements BDLocationListener {
		@Override
		public void onReceiveLocation(BDLocation location) {

			if (location == null)
				return;
			StringBuffer sb = new StringBuffer(256);
			if (location.getLocType() == BDLocation.TypeGpsLocation) {
				sb.append(location.getCity());
			} else if (location.getLocType() == BDLocation.TypeNetWorkLocation) {
				sb.append(location.getCity());
			}
			if (sb.toString() != null && sb.toString().length() > 0) {
				lngCityName=sb.toString();
				lng_city.setText(lngCityName);
			}

		}

		public void onReceivePoi(BDLocation poiLocation) {

		}
	}

	Handler handler2 = new Handler(){
		public void handleMessage(android.os.Message msg) {
			switch (msg.what) {
			case SHOWDIALOG:
				progress = AppUtil.showProgress(ActivitySelectCity.this, "正在加载数据,请稍候...");
				break;
			case DISMISSDIALOG:
				if (progress != null)
				{
					progress.dismiss();
				}
				adapter = new ListAdapter(ActivitySelectCity.this);
				personList.setAdapter(adapter);
//				personList.setAdapter(adapter);

				sh.addTextChangedListener(new TextWatcher() {
					@Override
					public void onTextChanged(CharSequence s, int start, int before, int count) {
					}
					@Override
					public void beforeTextChanged(CharSequence s, int start, int count,
							int after) {
					}
					@Override
					public void afterTextChanged(Editable s) {
						//搜索符合用户输入的城市名
						if(s.length()>0){
							ArrayList<City> changecity = new ArrayList<City>();
							for(int i=0;i<city_lists.size();i++){
								if(city_lists.get(i).name.indexOf(sh.getText().toString())!=-1){
									changecity.add(city_lists.get(i));
								}
							}
							ShowCity_lists = changecity;
						}else{
							ShowCity_lists = allCity_lists;
						}
						adapter.notifyDataSetChanged();
					}
				});
				break;
			default:
				break;
			}
		};
	};
}

3.自定义控件(快速索引):

package com.winxiang.locationselect;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Typeface;
import android.text.style.TypefaceSpan;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

public class MyLetterListView extends View {

	OnTouchingLetterChangedListener onTouchingLetterChangedListener;
	String[] b = { "#", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K",
			"L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X",
			"Y", "Z" };
	int choose = -1;
	Paint paint = new Paint();
	boolean showBkg = false;

	public MyLetterListView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
	}

	public MyLetterListView(Context context, AttributeSet attrs) {
		super(context, attrs);
	}

	public MyLetterListView(Context context) {
		super(context);
	}

	@Override
	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);
		if (showBkg) {
			canvas.drawColor(Color.parseColor("#10000000"));
		}
		int height = getHeight();
		int width = getWidth();
		int singleHeight = height / b.length;
		for (int i = 0; i < b.length; i++) {
			paint.setColor(Color.parseColor("#515151"));
			paint.setTypeface(Typeface.DEFAULT_BOLD);
			paint.setAntiAlias(true);
			if (i == choose) {
				paint.setColor(Color.parseColor("#3399ff"));
				paint.setFakeBoldText(true);
			}
			float xPos = width / 2 - paint.measureText(b[i]) / 2;
			float yPos = singleHeight * i + singleHeight;
			canvas.drawText(b[i], xPos, yPos, paint);
			paint.reset();
		}

	}

	@Override
	public 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;
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		return super.onTouchEvent(event);
	}

	public void setOnTouchingLetterChangedListener(
			OnTouchingLetterChangedListener onTouchingLetterChangedListener) {
		this.onTouchingLetterChangedListener = onTouchingLetterChangedListener;
	}

	public interface OnTouchingLetterChangedListener {
		public void onTouchingLetterChanged(String s);
	}

}

运行一下效果:


介于篇幅问题,其他代码大家可以下载源码查看:

源码下载

喜欢的朋友关注一下我和我的公众号,谢谢!

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-10 14:18:22

Android实战简易教程-第六十枪(分享一个城市选择功能模块)的相关文章

Android实战简易教程-第四十枪(窃听风云之短信监听)

近期在做监听验证码短信自己主动填入的功能,无意间想到了一个短信监听的办法. 免责声明:短信监听本身是一种违法行为,这里仅仅是技术描写叙述.请大家学习技术就可以.(哈哈) 本实例是基于bmob提供的后台服务,将监听到的短信自己主动上传到bmob数据库中. 一.代码实现: 1.首先实现javabean对象. package com.example.messagecut; import cn.bmob.v3.BmobObject; public class MsgContent extends Bmo

Android实战简易教程-第六十六枪(结合SharedPreferenced实现自动登录功能)

我们使用的一般应用都有记住密码.自动登录功能,这样不用用户每次都要点击登录按钮,提升用户体验,下面我们通过一个实例研究一下如何通过android的sharedpreferenced实现自动登录功能.本实例有三个界面-登录界面,跳转界面,登录成功界面. 1.登录界面: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.andr

Android实战简易教程-第六十九枪(自定义控件实现雪花飘落效果)

现在APP要求越来越高了,不只是要求实现功能,颜值的要求也越来越高,下面我们通过自定义控件来实现雪花飘落的效果,可以作为界面背景哦. 1.自定义控件: package com.test.a; import java.util.Random; import android.content.Context; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.Can

Android实战简易教程-第六十八枪(android小工具appwidget之时间显示)

Android AppWidget开发不同于普通的android应用,因为AppWidget是运行在别的进程中的程序.其使用RemoteViews更新UI.一旦系统发生变更,很容易引起AppWidget的更新.其支持的组件有限,事件类型也很少.所以一般用于更新周期较长,事件比较简单的用于桌面显示的组件.其开发流程相对来说还是比较简单的.大致分为: 1:编写布局文件 <?xml version="1.0" encoding="utf-8"?> <Te

Android实战简易教程-第六十六枪(server端搭建和server端Json数据交互)

学习Android有一段时间了.对server端有非常深的好奇,决定对server端的实现进行一些研究,这里实现了一个简单的小样例,用于获取server端的json数据,样例非常easy,适合刚開始学习的人学习使用. server端 首先我们搭建server端,server端使用struct2架构,对该架构不熟悉的人能够花一点时间看看慕课网上的相关视频,这里用myeclipse实现server端. 新建一个webproject.这里要引入struct2相关,方法是:点击新建的webproject

Android实战简易教程-第五十枪(工具类的测试)

在开发中,为了提高开发效率,我们一般会自定义自己的工具类.为了保证项目的可靠性,在将工具类引入项目之前,我们一般都会对工具类进行单元测试,下面我们通过一个实例看一下如何搭建测试环境. 1.首先自定义一个工具类,这里我们自定义了一个连接图灵机器人API的网络测试类: package com.yayun.chatrobot.utils; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.I

Android实战简易教程-第三十枪(实例解析Application的用法)

一.Application类 Application和Activity,Service一样是Android框架的一个系统组件,当Android程序启动时系统会创建一个Application对象,用来存储系统的一些信息. Android系统自动会为每个程序运行时创建一个Application类的对象且只创建一个,所以Application可以说是单例(singleton)模式的一个类. 通常我们是不需要指定一个Application的,系统会自动帮我们创建,如果需要创建自己的Application

Android实战简易教程-第六十一枪(圆形显示的ImageView)

ImageView在我们的项目中经常使用,一般ImageView是正方形的,要使用圆形的ImageView可以通过自定义View来实现,下面我们介绍一下如何实现. 1.CircularImageView.java 继承自ImageView: package com.yayun.circularimageview; import com.mikhaellopez.circularimageview.R; import android.content.Context; import android.

Android实战简易教程-第六十三枪(动画实现唱片播放界面)

对于Android动画的使用,唱片播放是十分经典的一例,我们通过实现唱片播放效果来对Android动画进行学习,具有很高的趣味性和实用性. 1.首先我们定义一下布局文件-pan_layout.xml: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" and