您的位置:首页 > 移动开发 > Android开发

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

2012-08-07 18:15 567 查看
首先还是老样子,我们先来看一些应用视图:







这个应用很酷吧,可以很方面我们找到所要的城市及实现天气查询订阅等.但是我要在这里提一下搜狐的意见了,这个错误很明显,城市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 。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息