首先还是老样子,我们先来看一些应用视图:
这个应用很酷吧,可以很方面我们找到所要的城市及实现天气查询订阅等.但是我要在这里提一下搜狐的意见了,这个错误很明显,城市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上传一下,如果需要点击 链接下载
- 1楼keyboard_workers4小时前
- 效果不错,支持.