我们在开发过程中兰冕会有选着城市地点等东西,这些都是常用的东西,所以我也就将他封装起来了先来看看效果吧

1.首先看下项目的结构:

2.看下整体的项目效果

三:主ativity

private Context context = LetterSortActivity.this;

	private ClearEditText mClearEditText;
	private TextView tv_mid_letter;
	private ListView listView;
	private MyLetterSortView right_letter;

	private ItemBeanAdapter mAdapter;
	private List<City> mlist = new ArrayList<City>();
	private InputMethodManager inputMethodManager;

	private View mCityContainer;
	private FrameLayout mSearchContainer;
	private ListView mSearchListView;
	private SearchCityAdapter mSearchCityAdapter;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		super.onCreate(savedInstanceState);
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		setContentView(R.layout.activity_main);
		initView();
		setLinstener();
		initData();
		fillData();
	}

	protected void initData() {

		getDataCity();
		mAdapter = new ItemBeanAdapter(this, mlist);
		listView.setEmptyView(findViewById(R.id.citys_list_load));
		listView.setAdapter(mAdapter);

	}

	protected void initView() {

		inputMethodManager = (InputMethodManager) this
				.getSystemService(Context.INPUT_METHOD_SERVICE);
		listView = (ListView) findViewById(R.id.list);
		mClearEditText = (ClearEditText) findViewById(R.id.et_msg_search);
		// 这里设置中间字母
		right_letter = (MyLetterSortView) findViewById(R.id.right_letter);
		tv_mid_letter = (TextView) findViewById(R.id.tv_mid_letter);
		right_letter.setTextView(tv_mid_letter);
		//搜索
		mCityContainer = findViewById(R.id.city_content_container);
		mSearchContainer = (FrameLayout) this.findViewById(R.id.search_content_container);
		mSearchListView = (ListView) findViewById(R.id.search_list);
		mSearchListView.setEmptyView(findViewById(R.id.search_empty));
		mSearchContainer.setVisibility(View.GONE);

	}

	protected void setLinstener() {

		// tv_reget_pwd.setOnClickListener(this);

		listView.setOnItemClickListener(new OnItemClickListener() {

			@Override
			public void onItemClick(AdapterView<?> parent, View view,
					int position, long id) {
				T.showShort(getApplicationContext(),
						((City) mAdapter.getItem(position)).toString());

			}
		});

		listView.setOnTouchListener(new OnTouchListener() {

			@Override
			public boolean onTouch(View v, MotionEvent event) {
				// 隐藏软键盘
				if (getWindow().getAttributes().softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN) {
					if (getCurrentFocus() != null)
						inputMethodManager.hideSoftInputFromWindow(
								getCurrentFocus().getWindowToken(),
								InputMethodManager.HIDE_NOT_ALWAYS);
				}
				return false;
			}
		});

		// 设置右侧触摸监听
		right_letter
				.setOnTouchingLetterChangedListener(new OnTouchingLetterChangedListener() {

					@Override
					public void onTouchingLetterChanged(String s) {
						// 该字母首次出现的位置
						int position = mAdapter.getPositionForSection(s
								.charAt(0));
						if (position != -1) {
							listView.setSelection(position);
						}

					}
				});

		// 根据输入框输入值的改变来过滤搜索
		mClearEditText.addTextChangedListener(new TextWatcher() {

			@Override
			public void onTextChanged(CharSequence s, int start, int before,
					int count) {
				// 当输入框里面的值为空,更新为原来的列表,否则为过滤数据列表
				filterData2(s.toString());
			}

			@Override
			public void beforeTextChanged(CharSequence s, int start, int count,
					int after) {

			}

			@Override
			public void afterTextChanged(Editable s) {
			}
		});

		mSearchListView
				.setOnItemClickListener(new android.widget.AdapterView.OnItemClickListener() {

					@Override
					public void onItemClick(AdapterView<?> parent, View view,
							int position, long id) {
						// TODO Auto-generated method stub
						// L.i(mSearchCityAdapter.getItem(position).toString());
						T.showLong(getApplicationContext(), mSearchCityAdapter
								.getItem(position).toString());
					}
				});
	}

	protected void fillData() {
		// TODO Auto-generated method stub

	}

	private void getDataCity() {

		new Thread(new Runnable() {

			@Override
			public void run() {
				MyCityDBHelper myCityDBHelper = new MyCityDBHelper(context);

				mlist = myCityDBHelper.getCityDB().getAllCity();
				mHandler.sendEmptyMessage(0);

			}
		}).start();

		// 对list进行排序
		// Collections.sort(mlist, new PinyinComparator() {
		// });

	}

	private void filterData2(String filterStr) {
		mSearchCityAdapter = new SearchCityAdapter(LetterSortActivity.this,
				mlist);
		mSearchListView.setAdapter(mSearchCityAdapter);
		mSearchListView.setTextFilterEnabled(true);
		if (mlist.size() < 1 || TextUtils.isEmpty(filterStr)) {
			mCityContainer.setVisibility(View.VISIBLE);
			mSearchContainer.setVisibility(View.INVISIBLE);

		} else {

			mCityContainer.setVisibility(View.INVISIBLE);
			mSearchContainer.setVisibility(View.VISIBLE);
			mSearchCityAdapter.getFilter().filter(filterStr);
		}
	}

	@Override
	public void onClick(View v) {
		switch (v.getId()) {
		//
		default:
			break;
		}

	}

	private Handler mHandler = new Handler() {
		public void handleMessage(android.os.Message msg) {
			switch (msg.what) {
			case 0:

				mAdapter.updateListView(mlist);
				break;
			default:
				break;
			}
		}
	};

四:编辑框view

public class ClearEditText extends EditText implements
       OnFocusChangeListener, TextWatcher {
	/**
	 * 删除按钮的引用
	 */
   private Drawable mClearDrawable; 

   public ClearEditText(Context context) {
   	this(context, null);
   } 

   public ClearEditText(Context context, AttributeSet attrs) {
   	//这里构造方法也很重要,不加这个很多属性不能再XML里面定义
   	this(context, attrs, android.R.attr.editTextStyle);
   } 

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

   private void init() {
   	//获取EditText的DrawableRight,假如没有设置我们就使用默认的图片
   	mClearDrawable = getCompoundDrawables()[2];
       if (mClearDrawable == null) {
       	mClearDrawable = getResources().getDrawable(R.drawable.search_clear);
       }
       mClearDrawable.setBounds(0, 0, mClearDrawable.getIntrinsicWidth(), mClearDrawable.getIntrinsicHeight());
       setClearIconVisible(false);
       setOnFocusChangeListener(this);
       addTextChangedListener(this);
   } 

   /**
    * 因为我们不能直接给EditText设置点击事件,所以我们用记住我们按下的位置来模拟点击事件
    * 当我们按下的位置 在  EditText的宽度 - 图标到控件右边的间距 - 图标的宽度  和
    * EditText的宽度 - 图标到控件右边的间距之间我们就算点击了图标,竖直方向没有考虑
    */
   @Override
   public boolean onTouchEvent(MotionEvent event) {
       if (getCompoundDrawables()[2] != null) {
           if (event.getAction() == MotionEvent.ACTION_UP) {
           	boolean touchable = event.getX() > (getWidth()
                       - getPaddingRight() - mClearDrawable.getIntrinsicWidth())
                       && (event.getX() < ((getWidth() - getPaddingRight())));
               if (touchable) {
                   this.setText("");
               }
           }
       } 

       return super.onTouchEvent(event);
   } 

   /**
    * 当ClearEditText焦点发生变化的时候,判断里面字符串长度设置清除图标的显示与隐藏
    */
   @Override
   public void onFocusChange(View v, boolean hasFocus) {
       if (hasFocus) {
           setClearIconVisible(getText().length() > 0);
       } else {
           setClearIconVisible(false);
       }
   } 

   /**
    * 设置清除图标的显示与隐藏,调用setCompoundDrawables为EditText绘制上去
    * @param visible
    */
   protected void setClearIconVisible(boolean visible) {
       Drawable right = visible ? mClearDrawable : null;
       setCompoundDrawables(getCompoundDrawables()[0],
               getCompoundDrawables()[1], right, getCompoundDrawables()[3]);
   } 

   /**
    * 当输入框里面内容发生变化的时候回调的方法
    */
   @Override
   public void onTextChanged(CharSequence s, int start, int count,
           int after) {
       setClearIconVisible(s.length() > 0);
   } 

   @Override
   public void beforeTextChanged(CharSequence s, int start, int count,
           int after) { 

   } 

   @Override
   public void afterTextChanged(Editable s) { 

   } 

   /**
    * 设置晃动动画
    */
   public void setShakeAnimation(){
   	this.setAnimation(shakeAnimation(5));
   }

   /**
    * 晃动动画
    * @param counts 1秒钟晃动多少下
    * @return
    */
   public static Animation shakeAnimation(int counts){
   	Animation translateAnimation = new TranslateAnimation(0, 10, 0, 0);
   	translateAnimation.setInterpolator(new CycleInterpolator(counts));
   	translateAnimation.setDuration(1000);
   	return translateAnimation;
   }

五:MyLetterSortView 字母

public class MyLetterSortView extends View {
	// 触摸事件
	private OnTouchingLetterChangedListener onTouchingLetterChangedListener;
	// 26个字母
	public static 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", "#" };
	private int choose = -1;// 选中
	private Paint paint = new Paint();

	private TextView mTextDialog;

	public void setTextView(TextView mTextDialog) {
		this.mTextDialog = mTextDialog;
	}

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

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

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

	/**
	 * 重写这个方法
	 */
	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);
		// 获取焦点改变背景颜色.
		int height = getHeight();// 获取对应高度
		int width = getWidth(); // 获取对应宽度
		int singleHeight = height / b.length;// 获取每一个字母的高度

		for (int i = 0; i < b.length; i++) {
			paint.setColor(Color.parseColor("#9da0a4"));
			paint.setTypeface(Typeface.DEFAULT_BOLD);
			paint.setAntiAlias(true);
	      //	paint.setTextSize(PixelUtil.sp2px(12));
	    	paint.setTextSize(25);

			// 选中的状态
			if (i == choose) {
				paint.setColor(Color.parseColor("#3399ff"));
				paint.setFakeBoldText(true);
			}
			// x坐标等于中间-字符串宽度的一半.
			float xPos = width / 2 - paint.measureText(b[i]) / 2;
			float yPos = singleHeight * i + singleHeight;
			canvas.drawText(b[i], xPos, yPos, paint);
			paint.reset();// 重置画笔
		}

	}

	@SuppressWarnings("deprecation")
	@Override
	public boolean dispatchTouchEvent(MotionEvent event) {
		final int action = event.getAction();
		final float y = event.getY();// 点击y坐标
		final int oldChoose = choose;
		final OnTouchingLetterChangedListener listener = onTouchingLetterChangedListener;
		final int c = (int) (y / getHeight() * b.length);// 点击y坐标所占总高度的比例*b数组的长度就等于点击b中的个数.

		switch (action) {
		case MotionEvent.ACTION_UP:
			setBackgroundDrawable(new ColorDrawable(0x00000000));
			choose = -1;//
			invalidate();
			if (mTextDialog != null) {
				mTextDialog.setVisibility(View.INVISIBLE);
			}
			break;

		default:
			//设置右侧字母列表[A,B,C,D,E....]的背景颜色
			setBackgroundResource(R.drawable.letter_sort_background);
			if (oldChoose != c) {
				if (c >= 0 && c < b.length) {
					if (listener != null) {
						listener.onTouchingLetterChanged(b[c]);
					}
					if (mTextDialog != null) {
						mTextDialog.setText(b[c]);
						mTextDialog.setVisibility(View.VISIBLE);
					}

					choose = c;
					invalidate();
				}
			}

			break;
		}
		return true;
	}

	/**
	 * 向外公开的方法
	 *
	 * @param onTouchingLetterChangedListener
	 */
	public void setOnTouchingLetterChangedListener(
			OnTouchingLetterChangedListener onTouchingLetterChangedListener) {
		this.onTouchingLetterChangedListener = onTouchingLetterChangedListener;
	}

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

还有一部分代码比较多,就不一一贴上了.

源码地址:城市选择源码

android 城市选择的更多相关文章

  1. Android之自定义控件-城市选择

    实现效果: 图片素材:           --> 首先, 城市数据字节放在 Json 文件, 就不网络获取了. city.json 存放 Json 数据: { "result&quo ...

  2. 【Android开源库】美团等APP城市选择

    CityPicker 现在使用比较多的类似美团等APP的城市选择界面. 2步即可实现,就是这么简单粗暴! Gif image APK 下载demo.apk体验. Install Gradle: com ...

  3. android wheelview实现三级城市选择

    很早之前看淘宝就有了ios那种的城市选择控件,当时也看到网友有分享,不过那个写的很烂,后来(大概是去年吧),我们公司有这么一个项目,当时用的还是网上比较流行的那个黑框的那个,感觉特别的丑,然后我在那个 ...

  4. ionic-基于angularjs实现的多级城市选择组件

    大家都知道在移动端的选择地区组件,大部分都是模拟IOS选择器做的城市三级联动,但是在IOS上比较好,在Android上因为有的不支持ion-scroll.所以就会出现滚动不会自动回滚到某一个的正中间. ...

  5. 移动端城市选择JavaScript插件(基于WG的城市选择插件的修改版本)

    周末的时候趁着一次机会,拿WG(博客)开发的城市选择插件改了一个移动端可以直接用的城市选择插件. 原版插件是基于原声JavaScript写的,在此先感谢作者. 我做的只是依照肯德基注册会员的页面的交互 ...

  6. UIPIckerView现实城市选择

    实现城市选择,选中省时,后来自动显示相对应的城市,并且下面会打印出来对应的省和城市 . 因为plist里面是一个一个的字典. 1.字典转模型 HMCities.h #import <Founda ...

  7. 仿51job.com城市选择框特效

    650) this.width=650;" border="0" alt="" src="http://img1.51cto.com/att ...

  8. 选择Android还是选择JavaEE?

    很多同学咨询过同样的一个问题,该问题也是最备受争议的问题,那就是到底是选择Android还是选择JavaEE.下面发表一些本人的看法.       Android属于一个特有的Java技术应用,专注于 ...

  9. 纯原生js移动端城市选择插件

    接着上一篇纯js移动端日期选择插件,话说今天同事又来咨询省市县联动的效果在移动端中如何实现,还是老样子,百度上一搜,诶~又全是基于jquery.zepto的,更加可恨的是大多数都是PC版的,三个sel ...

随机推荐

  1. go panic recover 异常处理

    Go语言追求简洁优雅,所以,Go语言不支持传统的 try…catch…finally 这种异常,因为Go语言的设计者们认为,将异常与控制结构混在一起会很容易使得代码变得混乱.因为开发者很容易滥用异常, ...

  2. 20145310《Java程序设计》第3周学习总结

    20145310 <Java程序设计>第3周学习总结 教材学习内容总结 本周学习内容比较多,主要是第四第五章的学习. 第四章 类与对象 类是对象的设计图,对象是类的实例. 类(Class) ...

  3. 20135320赵瀚青LINUX第六周学习笔记

    赵瀚青原创作品转载请注明出处<Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 概述 这周主要讲解的是进程. ...

  4. COGS314. [NOI2004] 郁闷的出纳员

    ★★★   输入文件:cashier.in   输出文件:cashier.out   简单对比 时间限制:1 s   内存限制:128 MB [问题描述] OIER公司是一家大型专业化软件公司,有着数 ...

  5. 从零开始玩转JMX(三)——Model MBean

    Model MBean 相对于Standard MBean,Model MBean更加灵活.如果我们不能修改已有的Java类,那么使用Model MBean是不错的选择. Model MBean也是一 ...

  6. Juniper SRX防火墙简明配置手册(转)

    在执行mit命令前可通过配置模式下show命令查看当前候选配置(Candidate Config),在执行mit后配置模式下可通过run show config命令查看当前有效配置(Active co ...

  7. 缓存技术内部交流_04_Cache Aside续篇

    额外参考资料: http://www.ehcache.org/documentation/3.2/expiry.html F. Cache Aside 模式的问题:缓存过期 有时我们会在上线前给缓存系 ...

  8. JavaScript内部原理系列-执行上下文(Execution Context)

    概要 本文将向大家介绍ECMAScript的执行上下文以及相关的可执行代码类型. 定义 每当控制器到达ECMAScript可执行代码的时候,控制器就进入了一个执行上下文.执行上下文(简称:EC)是个抽 ...

  9. Codeforces Round #349 (Div. 2)

    第一题直接算就行了为了追求手速忘了输出yes导致wa了一发... 第二题技巧题,直接sort,然后把最大的和其他的相减就是构成一条直线,为了满足条件就+1 #include<map> #i ...

  10. IOS-APP主流UI框架结构

    一.简单示例 说明:使用APP主流UI框架结构完成简单的界面搭建 搭建页面效果:                                二.搭建过程和注意点 1.新建一个项目,把原有的控制器删 ...