六.自定义View之城市列表快速检索

在城市列表的快速检索项目中,左侧的26个英文字母Bar是自己画出来的,因此暂且把这个小项目也归类到自定义View中吧。

项目逻辑:

1.左边是一个自定义从A-Z的快速索引,它能够获取到触摸它的时候获取到的字母的索引。

2.右边是一个ListView,按照字母分类排序里面的内容,并且根据触摸的字母,去自己列表找首字母和触摸字母相同的那个

item,然后让item放置到屏幕顶端(setSelection(position));

3.需要用到文字转拼音。

下面就开始来一步步的实现这个功能吧。

一、自定义26个字母索引View:QuickIndexBar

1)绘制文字:使用canvas.drawText(text,x,y,paint)来实现。其中x,y在默认情况下(Paint.Align.LEFT模式下)分别是所绘制的文字左下角的坐标。


7753368-5ab91cf676f53a0a.png

通过上图可以分析出,画文字时的x,y坐标的值,x值就是自定义View宽度的一半:getMeasureWidth/2, y值是格子高度/2 + 文字高度/2 ,如果是B之后的字母,还需要加上格子的高度,因此,我们可以得到y值:格子高度/2 + 文字高度/2 + position*格子高度

在竖直方向上,我们要把26个字母平均分配到自定义View中,因此每个格子的高度是getMeasureHeight()/26,重点是求文本的高度。

获取x值和格子的高度:

7753368-11e97e69981d5bdd.png

在自定义View中用canvas绘制文字时,可以通过这样一个方法去获得文字的高度:

7753368-8ca300dc4a532811.png
获取文字高度

定义一个矩形bounds,当这个方法执行完成之后,我们所要测量的文字就满满的填充在bounds之中,此时我们获取矩形的高度即可以得到文字的高度。

7753368-4df6fd97bc30bdbb.png
获取文本高度

高度获取之后,我们就可以来绘制文字了。

初始化画笔,可以设置文字的大小,颜色等。

7753368-6edae944c3eba7f6.png
初始化画笔


7753368-45ecabe0abb28c13.png
画出文字

效果图:

7753368-dcf9c74688a659a2.png
左侧索引栏

2)按下和移动时计算触摸字母Bar时对应的字母值。(int)按下的y值/cellHeight就是字母的position,移动时也是这样一个逻辑,但是手指在屏幕上移动会产生无数个移动事件,这里就需要控制一下,只有当position改变时,才获取字母的值。

7753368-c92780220efbc829.png

实现每次选中的字母都会变色,在每一次移动,按下,抬起时都要重绘界面,在onDraw()中判断 lastIndex == i ,如果相等那么重绘时,把第i个字母的颜色改变,其他字母仍然是黑色。

7753368-34c1b831454286fe.png

3)设置回调,把每次获取的字母传出去,用于与外界的ListView的数据交互。

编写接口和setXXXListener()

7753368-bb95bb0f63ba2516.png

在获取字母的地方,调用接口中的方法,把数据传递出去。

7753368-8cbeb518df660c4d.png

在外界获取数据。

7753368-604e948624537568.png

这里有关于字母索引条的开发就完成了,下面开始左侧ListView的开发。

二、左侧ListView的开发

1)设置ListView的Item

左侧ListView的Item分为上下两部分,上部分是显示首字母,下部分是显示名称。如图,下部分填充的是姓名,上部分填充的是姓名的首字母。

7753368-3008581a3eade7d2.png

2)将姓名转化成拼音,使用到的是pinyin4j.jar

7753368-c1f0a554774cbe97.png
把汉字转换成拼音

在Adapter中设置数据

7753368-9e4ffa8b8c394199.png

此时效果图是这样的

7753368-2a24590d1e78ab33.png

3)对姓名进行排序

使用Collections中的sort(),但是该方法要求参数中的实体类必须实现 Comparable<T>接口,实现其中的compareTo()

7753368-7270cee7e4c377b7.png


7753368-4fc128c7b238fafa.png

4)对于相同首字母的条目,item上部分显示字母的部分只留一个,其它隐藏起来。跟上一个Item比较,如果是相同的首字母就要隐藏上半部分


7753368-dafa376fbe53f56f.png

此时的效果图

7753368-bd08a7d8d25e0d2f.png

5)手指点击或移动到某个字母上,ListView会把相应首字母的Item放置屏幕的顶端

7753368-3d789ca3c7c1dc56.png

6)点击相应的字母,屏幕中间弹出对话框,这里屏幕中间的对话框使用TextView,没有点击的情况下,TextView是隐藏状态,当需要显示TextView时,显示出来

7753368-996fe2b6725f8af2.png

效果图:

7753368-78a5826a4569f918.gif





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
package cc.lifelink.cn; import java.util.ArrayList; import java.util.List; import android.app.Activity; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.graphics.drawable.BitmapDrawable; import android.os.Bundle; import android.util.Log; import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.widget.AdapterView; import android.widget.AdapterView.OnItemSelectedListener; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ListView; import android.widget.PopupWindow; import android.widget.Spinner; import android.widget.TextView; import android.widget.Toast; public class City_cnActivity extends Activity { private DBManager dbm; private SQLiteDatabase db; private Spinner provinceSpinner; private Spinner citySpinner=null; private Spinner districtSpinner=null; private String province=null; private String city=null; private String district=null; /*------------------*/ // private TextView provinceView; // private TextView cityView; // private TextView districtView; // private ImageView provinceImageView; // private ImageView cityImageView; // private ImageView districtImageView; // // private PopupWindow mPopupWindow; // private ListView provinceListView /*------------------*/ public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); provinceSpinner=(Spinner)findViewById(R.id.spinner1); citySpinner=(Spinner)findViewById(R.id.spinner2); districtSpinner=(Spinner)findViewById(R.id.spinner3); provinceSpinner.setPrompt("鐪?鐩磋緰甯?); citySpinner.setPrompt("鍩庡競"); districtSpinner.setPrompt("鍦板尯"); provinceSpinner.setOnItemSelectedListener(new ProvinceOnSelectedListener()); districtSpinner.setOnItemSelectedListener(new DistrictOnSelectedListener()); citySpinner.setOnItemSelectedListener(new CityOnSelectedListener()); dbm = new DBManager(this); provinceSpinner(); // initUI(); } // private void initUI(){ // provinceView = (TextView) findViewById(R.id.tv_province); // cityView = (TextView) findViewById(R.id.tv_city); // districtView = (TextView) findViewById(R.id.tv_district); // provinceImageView = (ImageView) findViewById(R.id.iv_province); // cityImageView = (ImageView) findViewById(R.id.iv_city); // districtImageView = (ImageView) findViewById(R.id.iv_district); // // LayoutInflater inflater = LayoutInflater.from(this); // LinearLayout prvinceLayout = (LinearLayout) View.inflate(this, R.layout.popup_province, null); // provinceListView = (ListView) prvinceLayout.findViewById(R.id.lv_province); // mPopupWindow = new PopupWindow(prvinceLayout, 150, 280); // mPopupWindow.setBackgroundDrawable(new BitmapDrawable()); // mPopupWindow.setFocusable(true); // mPopupWindow.setOutsideTouchable(true); // mPopupWindow.update(); // } // // private class ImageViewClickListener implements OnClickListener{ // // // @Override // public void onClick(View v) { // switch (v.getId()) { // case R.id.iv_province: // mPopupWindow.showAtLocation(mLinearLayout, Gravity.LEFT // | Gravity.TOP, arrayOfInt[0]+10, arrayOfInt[1]+41); // break; // case R.id.iv_city: // // break; // case R.id.iv_district: // // break; // // default: // break; // } // } // // } public void provinceSpinner(){ dbm.openDatabase(); db = dbm.getDatabase(); Cursor cursor=null; List<CommonItem> provinces = new ArrayList<CommonItem>(); try { String sql = "select * from province"; cursor = db.rawQuery(sql,null); while (cursor.moveToNext()){ String code=cursor.getString(cursor.getColumnIndex("code")); int id = cursor.getInt(cursor.getColumnIndex("id")); Log.i("tag", "id: "+id+"code: "+code); byte bytes[]=cursor.getBlob(2); String name=new String(bytes,"gbk"); CommonItem myListItem=new CommonItem(); myListItem.setName(name); myListItem.setPcode(code); provinces.add(myListItem); } Log.i("tag", "provinces size: "+provinces.size()); } catch (Exception e) { e.printStackTrace(); } finally{ dbm.closeDatabase(); db.close(); if (cursor!=null) { cursor.close(); } } CommonAdapter provinceAdapter = new CommonAdapter(this,provinces); provinceSpinner.setAdapter(provinceAdapter); } public void citySpinner(String pcode){ Cursor cursor = null; List<CommonItem> citys = new ArrayList<CommonItem>(); try { dbm.openDatabase(); db = dbm.getDatabase(); String sql = "select * from city where pcode='"+pcode+"'"; cursor = db.rawQuery(sql,null); while (cursor.moveToNext()){ String code=cursor.getString(cursor.getColumnIndex("code")); byte bytes[]=cursor.getBlob(2); String name=new String(bytes,"gbk"); CommonItem myListItem=new CommonItem(); myListItem.setName(name); myListItem.setPcode(code); citys.add(myListItem); } Log.i("tag", "citys size: "+citys.size()); } catch (Exception e) { e.printStackTrace(); } finally{ dbm.closeDatabase(); db.close(); if (cursor!=null) { cursor.close(); } } CommonAdapter cityAdapter = new CommonAdapter(this,citys); citySpinner.setAdapter(cityAdapter); } public void districtSpinner(String pcode){ Cursor cursor=null; List<CommonItem> districts = new ArrayList<CommonItem>(); try { dbm.openDatabase(); db = dbm.getDatabase(); String sql = "select * from district where pcode='"+pcode+"'"; cursor = db.rawQuery(sql,null); while (cursor.moveToNext()){ String code=cursor.getString(cursor.getColumnIndex("code")); byte bytes[]=cursor.getBlob(2); String name=new String(bytes,"gbk"); CommonItem myListItem=new CommonItem(); myListItem.setName(name); myListItem.setPcode(code); districts.add(myListItem); } Log.i("tag", "districts size: "+districts.size()); } catch (Exception e) { e.printStackTrace(); } finally{ dbm.closeDatabase(); db.close(); if (cursor!=null) { cursor.close(); } } CommonAdapter districtAdapter = new CommonAdapter(this,districts); districtSpinner.setAdapter(districtAdapter); } class ProvinceOnSelectedListener implements OnItemSelectedListener{ public void onItemSelected(AdapterView<?> adapterView, View view, int position, long id) { province=((CommonItem) adapterView.getItemAtPosition(position)).getName(); String pcode =((CommonItem) adapterView.getItemAtPosition(position)).getPcode(); citySpinner(pcode); districtSpinner(pcode); } public void onNothingSelected(AdapterView<?> adapterView) { } } class CityOnSelectedListener implements OnItemSelectedListener{ public void onItemSelected(AdapterView<?> adapterView, View view, int position, long id) { city=((CommonItem) adapterView.getItemAtPosition(position)).getName(); String pcode =((CommonItem) adapterView.getItemAtPosition(position)).getPcode(); districtSpinner(pcode); } public void onNothingSelected(AdapterView<?> adapterView) { } } class DistrictOnSelectedListener implements OnItemSelectedListener{ public void onItemSelected(AdapterView<?> adapterView, View view, int position, long id) { district=((CommonItem) adapterView.getItemAtPosition(position)).getName(); Toast.makeText(City_cnActivity.this, province+" "+city+" "+district, Toast.LENGTH_LONG).show(); } public void onNothingSelected(AdapterView<?> adapterView) { } } @Override protected void onDestroy() { dbm=null; super.onDestroy(); } }

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值