android listview实现快速查询A—Z (模拟一些天气搜狐,网易等天气预报)

首先还是老样子,我们先来看一些应用视图:

                        

       这个应用很酷吧,可以很方面我们找到所要的城市及实现天气查询订阅等.但是我要在这里提一下搜狐的意见了,这个错误很明显,城市J开头的你却用I来提示,而J你pass掉了,看来还是网易比较好.不东扯西扯了.

       首先我们要实现右边提示的view,这里面我们要自定义,这里是参考别人的. 

       代码片段:

public class MySideBar extends View {

	private TextView textView;// 显示框

	private boolean showBkg = false;
	// 触摸事件
	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" };
	int choose = -1;// 选中
	Paint paint = new Paint();

	// 自定义view 最好注明这三个构造函数
	public MySideBar(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
	}

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

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

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

		for (int i = 0; i < b.length; i++) {
			paint.setColor(Color.BLACK);
			// paint.setColor(Color.WHITE);
			paint.setTypeface(Typeface.DEFAULT_BOLD);
			paint.setAntiAlias(true);
			paint.setTextSize(20);
			// 选中的状态
			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();// 重置画笔
		}

	}

	@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_DOWN:
			showBkg = true;
			if (oldChoose != c && listener != null) {
				if (c > 0 && c < b.length) {

					listener.onTouchingLetterChanged(b[c]);// 执行onTouchingLetterChanged事件.
					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();
			textView.setVisibility(View.GONE);
			break;
		}
		return true;
	}

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

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

	/**
	 * 接口
	 * 
	 * @author coder
	 * 
	 */
	public interface OnTouchingLetterChangedListener {
		public void onTouchingLetterChanged(String s);
	}

}


 注释很详细,我想大家一看就OK了.

 下面我们要实现主页面的内容.

      看到这个样式,我郁闷好久,用什么来实现呢,之前做过这个.android 解决ScrollView与ListView的冲突(TableLayout+ScrollView) 。所以就想到用Listview +TableView,结果遇到了一大堆问题,后来反过来用也是,总结一句话控件没学好,如果学的深的话,这些都可以解决的,有时间得用这几种方式做做.也许最简单的实现是“ListView嵌套ListView”.

      这里面肯定会出现问题,就是item显示的问题.         

    下面是实现代码:(声明,有点乱,不过都不难,我想你OK没问题)

     实现ListView的适配器.

/***
	 * 自定义Adapter
	 * 
	 * @author zhangjia
	 * 
	 */
	class MyAdapter extends BaseAdapter {
		private Context context;

		public MyAdapter(Context context) {
			super();
			this.context = context;
		}

		@Override
		public int getCount() {
			return MySideBar.b.length;
			// return MySideBar.b.length;
		}

		@Override
		public Object getItem(int position) {
			// TODO Auto-generated method stub
			return null;
		}

		@Override
		public long getItemId(int position) {
			// TODO Auto-generated method stub
			return 0;
		}

		@Override
		public View getView(int position, View convertView, ViewGroup parent) {
			TextView textView;
			if (convertView == null) {
				holder = new ViewHolder();
				convertView = (LinearLayout) LayoutInflater.from(context)
						.inflate(R.layout.item, null);
				holder.textView = (TextView) convertView
						.findViewById(R.id.tv_item);
				holder.listView = (ListView) convertView
						.findViewById(R.id.lv_item);
				convertView.setTag(holder);
			} else {
				holder = (ViewHolder) convertView.getTag();
			}
			final String textValue = mySideBar.b[position];// A...B...C
			// 显示该控件
			holder.textView.setVisibility(View.VISIBLE);
			holder.listView.setVisibility(View.VISIBLE);
			if (position == 0) {
				holder.textView.setText("当前城市");
			} else {
				holder.textView.setText(textValue);
			}
			child = getListView(textValue);
			holder.listView.setAdapter(child);
			// 设置样式(宽度)
			setListViewHeightBasedOnChildren(holder.listView);

			if (child.getCount() == 0) {
				// 没有项的让该控件消失
				holder.textView.setVisibility(View.GONE);
				holder.listView.setVisibility(View.GONE);
			}

			holder.listView.setOnItemClickListener(new OnItemClickListener() {
				@Override
				public void onItemClick(AdapterView<?> parent, View view,
						int position, long id) {
					// parent.getItemAtPosition(position).toString();根据item提示,这样万无一失
					Toast.makeText(MainActivity.this,
							parent.getItemAtPosition(position).toString(), 1000)
							.show();
				}
			});
			return convertView;
		}
	}
在这里我们会遇到一个问题就是listivew中嵌套listview,显示我们需要对listview进行动态设置ilistview的高度.

/***
	 * 动态设置listview的高度
	 * 
	 * @param listView
	 */
	public void setListViewHeightBasedOnChildren(ListView listView) {
		ListAdapter listAdapter = listView.getAdapter();
		if (listAdapter == null) {
			return;
		}
		int totalHeight = 0;
		for (int i = 0; i < listAdapter.getCount(); i++) {
			View listItem = listAdapter.getView(i, null, listView);
			listItem.measure(0, 0);
			totalHeight += listItem.getMeasuredHeight();
		}
		ViewGroup.LayoutParams params = listView.getLayoutParams();
		params.height = totalHeight
				+ (listView.getDividerHeight() * (listAdapter.getCount() - 1));
		// params.height += 5;// if without this statement,the listview will be
		// a
		// little short
		// listView.getDividerHeight()获取子项间分隔符占用的高度
		// params.height最后得到整个ListView完整显示需要的高度
		listView.setLayoutParams(params);
	}
这样外面的listview就会根据子listview的高度定制自己的高度.

 调用代码(实现OnTouchingLetterChangedListener接口)

	@Override
	public void onTouchingLetterChanged(String s) {
		overlay.setText(s);
		overlay.setBackgroundColor(Color.GRAY);
		overlay.setVisibility(View.VISIBLE);
		int position = arrayList.indexOf(s);
		lvMain.setSelection(position);
	}
@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		InitView();//初始view

		et_main.addTextChangedListener(textWatcher);

		cityManager.InitData();// 创建数据库
		adapter = new MyAdapter(this);
		lvMain.setAdapter(adapter);

		arrayList = new ArrayList<String>();
		for (int i = 0; i < MySideBar.b.length; i++) {
			arrayList.add(MySideBar.b[i]);
		}
	}
以上就是主要实现代码.


   项目展示:

                     

       看起来还凑合吧,最近想实现个完整的天气项目,就先搭一下架子了.哈哈.

      代码都在上面,我就不多解释了,还有一点我需要说明一下,里面的数据我们可以通过天气预报接口进行解析获取相应的城市.

解析就是请求,解析字符串,就不多说了,但是我还要明确一点就是对字母的查询,我们要获取城市的pinyin.这个是比较头疼的,虽说已经有pingyin4j.jar了,但是比较窝囊的是,多音字没有解决,为了解决这个,我走了好多弯路,用到了翻译接口,请求webservice,因为中国地名就是拼音嘛,虽知道我自错聪明,好不容易搭好了架子,虽知道解析有的偏僻地方都没有英文,我郁闷个头啊.最后解决了80%,至于方法,我不说你也知道.

     这里我把city.db上传一下,如果需要点击      链接下载


/*********************************************************************************************************************************************/

最近参考别的的实现,觉得我上面这种做法很复杂,完全没有必要用listview 嵌套listview,其实我们完全用listview就可以实现,只是对getView返回view的时候坐下判断就可以了,下面我简单介绍下,不管有没有用,总之对我很有用啊,哈哈.因为我上面那种实现起来麻烦.

首先我们先制造数据:

public void setData() {
		list.add("A");
		listTag.add("A");
		for (int i = 0; i < 5; i++) {
			list.add("ANDROID" + i);
		}
		list.add("B");
		listTag.add("B");
		for (int i = 0; i < 5; i++) {
			list.add("IPHONE" + i);
		}
		list.add("C");
		listTag.add("C");
		for (int i = 0; i < 5; i++) {
			list.add("WINDOW" + i);
		}
这样做的目的是让我们listview显示的时候可以指定某一个item进行自我操作.

	@Override
		public View getView(int position, View convertView, ViewGroup parent) {
			View view = convertView;
			if (listTag.contains(getItem(position))) {
				view = LayoutInflater.from(getContext()).inflate(
						R.layout.group_list_item_tag, null);
			} else {
				view = LayoutInflater.from(getContext()).inflate(
						R.layout.group_list_item, null);
			}
			TextView textView = (TextView) view
					.findViewById(R.id.group_list_item_text);
			textView.setText(getItem(position));
			return view;
		}
也很好理解,因为我们在setData的时候已经把数据标记好了,所以可以在指定的一行进行显示相应的样式.

结果样式:

    
效果和上面差不多吧,我感觉这种实现起来方便多了,所以建议大家使用这种,不过上面那种也不复杂,就是对listview显示的时候稍微处理下就ok了.


如果有不足之处,留言指出,  

想要源码请留邮箱.Thanks for you 。




  • 19
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 85
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 85
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值