本文主要是介绍一款很实用的小demo 字母条索引+自定义进度条+listview/checkbox+长按多选+读取联系人\头像,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
点击打开链接,免费下载demo代码
先贴上一张GIf动图(效果不是很理想,我是用的asm手机映射到电脑上的)
接下来就一步步简单的说下思路吧:action开始
void createTables(SQLiteDatabase db) { String sql = "CREATE TABLE IF NOT EXISTS " + TABLE_NAME_CONTACT + " (" + BaseColum.ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " + BaseColum.NAME + " TEXT, " + BaseColum.PHONE+ " TEXT, " + BaseColum.SORT_KEY+ " TEXT, " + BaseColum.PHOTO_BYTE+ " blob, " + BaseColum.CONTACT_ID + " LONG" + ")"; db.execSQL(sql); }
1、首先在DataBaseHelper创建数据库,BaseColum.PHOTO_BYTE+ " blob系统联系人头像在系统数据库中是已byte二进制数组存储的,项目的数据库也是同样的存储方式,另外插入数据库的方法,就不解释了,代码中有的。
2、在ContactsManager中getLocalContacts方法是获取系统手机联系人的方法,关于系统通讯录的一些方法,可以参考
获取系统手机联系人的方法
我这个demo是用的 Uri uri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;这个url有个问题,就是系统联系人如果是不存电话的,是获取不到的,
如果产品要求那些空号码的联系人也获取只能用其他的方法了,可以用
- /**
- * 通过contactId从data表中获取联系人信息 Uri uri =
- * Uri.parse("content://com.android.contacts/contacts/#/data");
- * 查询contacts表获取contactId, 通过contact_id去获取data表中相应的数据
- */
3、另外初始化就是导入联系人,出现自定义的进度条,插入本地数据库,然后进行ui更新界面,GLauncherExectorManger这个是一些线程池的操作
创建一个线程池,然后添加任务
4、插入联系人是实时更新进度条的,用的是异步任务操作
importSum += ContactSqliteManager.getInstance().insertContact(contactInfo);publishProgress(importSum);
在自定义进度条中importingDialog.notifyByteProgress(localContacts.size(), values[0]);
进行实时更新进度条界面,在notifyByteProgress方法里面mCustomProgressBar.setProgress(percent);,是去更新那个进度条的进度的
然后在去绘制那个进度条目
protected void onDraw(Canvas canvas) {if ((this.barBg != null)) {canvas.drawBitmap(this.barBg, 0.0F, 0.0F, null);}super.onDraw(canvas);}
GLauncherExectorManger.getInstance().addTask(new Runnable() {@Overridepublic void run() {contactsFromInternal = ContactSqliteManager.getInstance().getContactsFromInternal();updateUiHandler.sendEmptyMessage(0);}});
然后在handler里面进行操作初始化
private Handler updateUiHandler = new Handler() {public void handleMessage(android.os.Message msg) {if (msg.what == 0) {LogUtils.i(LOG_TAG, "contactsFromInternal.size-->>"+ contactsFromInternal.size());contactAdapter = new ContactsListAdapter(MainActivity.this,contactsFromInternal, alphabeticBar, false);mListView.setAdapter(contactAdapter);mListView.setDividerHeight(0);// 初始化字母条alphabeticBar.init(MainActivity.this);alphabeticBar.setListView(mListView);alphabeticBar.setVisibility(View.VISIBLE);}};};
6、接下来看那个字幕条吧、在QuickAlphabeticBar中有如下方法
// 初始化public void init(Activity ctx) {mDialogText = (TextView) ctx.findViewById(R.id.tv_contact_list_fast_position);if (mDialogText != null)mDialogText.setVisibility(View.INVISIBLE);mHandler = new Handler();}// 设置需要索引的列表public void setListView(ListView mList) {this.mList = mList;}
/*** String:sortKey Integer:listsContact的角标索引private HashMap<String,Integer> alphaIndexer;*/public void setAlphaIndexer(HashMap<String, Integer> alphaIndexer) {this.alphaIndexer = alphaIndexer;postInvalidate() ;}
setAlphaIndexer是在适配器中进行操作赋值的
就是去判断界面上的联系人的一个map集合,这个集合,是sortkey和角标的键值对,这样可以去实现点击效果的字幕条,去判断对应的索引位置的contact
if (selectIndex > -1 && selectIndex < letters.length) {// 防止越界String key = letters[selectIndex];//获取手指触碰点的字母索引if (alphaIndexer.containsKey(key)) {int pos = alphaIndexer.get(key);//获取contactList的对应字母索引的角标if (mList.getHeaderViewsCount() > 0) {this.mList.setSelection(pos+mList.getHeaderViewsCount());} else {this.mList.setSelection(pos);//使listview移动到索引对应的contactList的角标位置}mDialogText.setBackgroundResource(array_drawables[selectIndex]);}}
7、接下里看长按对选操作吧,我这里之前有一个小bug,就是长按条目,mListView.setOnItemLongClickListener(new OnItemLongClickListener()和在适配器中
viewHolder.re_item_all.setOnClickListener会有冲突的,我的解决如下
if (isMultiChoice) {viewHolder.re_item_all.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {if(viewHolder.cb_check.isChecked()){viewHolder.cb_check.setChecked(false);}else{viewHolder.cb_check.setChecked(true);}}});}
处理一个标记,长按不走此方法,长按进入多选操作,在走此方法,网上还有一些其他的方法,大家可以试试
8、另外还有一个bug是这样的,就是listview+checkbox的头像错乱,和checkbox的选中状态随着listview的滑动改变异常
我处理方案是viewHolder.cb_check.setOnCheckedChangeListener放在适配器的最前面
后面在进行
if (isMultiChoice) {viewHolder.cb_check.setVisibility(View.VISIBLE);if(getIsSelected()!=null && getIsSelected().size()>0){viewHolder.cb_check.setChecked(getIsSelected().get(listsContact.get(position).getContactId()));}}else {viewHolder.cb_check.setVisibility(View.GONE);}/*** 解决setOnItemLongClickListener 跟setOnClickListener的冲突事件*/if (isMultiChoice) {viewHolder.re_item_all.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {if(viewHolder.cb_check.isChecked()){viewHolder.cb_check.setChecked(false);}else{viewHolder.cb_check.setChecked(true);}}});}
############################################# 以下是堆代码区,为了自己将来复制粘贴用########################################
首先先看下主界面的布局文件吧
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:background="#e6e6e6"tools:context="com.example.contactslistview.MainActivity" ><include android:id="@+id/search_select"layout="@layout/search_delete" /><ListViewandroid:id="@+id/mListView"android:layout_below="@id/search_select"android:layout_width="fill_parent"android:layout_alignParentLeft="true"android:layout_marginRight="20dp"android:layout_height="fill_parent" ></ListView><com.example.contactslistview.bean.QuickAlphabeticBarandroid:id="@+id/contact_list_fast_scroller"android:layout_width="20dp"android:layout_height="match_parent"android:layout_alignParentRight="true"android:background="@drawable/alphabetic_bg"android:layout_alignTop="@id/mListView"android:scaleType="centerInside"></com.example.contactslistview.bean.QuickAlphabeticBar><TextViewandroid:text=""android:id="@+id/tv_contact_list_fast_position"android:layout_width="70dip"android:layout_height="70dip"android:layout_centerInParent="true"android:gravity="center"android:textColor="#404040"android:textSize="48dip"android:typeface="sans"android:visibility="invisible" /><RelativeLayoutandroid:background="@drawable/delete_btn_bg"android:visibility="gone"android:id="@+id/ll_button"android:layout_width="match_parent"android:layout_height="122dp"android:layout_alignParentBottom="true"android:gravity="center_horizontal|bottom"><TextViewandroid:id="@+id/tv_cancel"android:layout_width="163.33dp"android:layout_height="40dp"android:layout_marginBottom="30dp"android:gravity="center"android:background="@drawable/selector_cancel"android:text="取消"android:textColor="#333333"android:textSize="16sp"/><TextViewandroid:id="@+id/tv_sure"android:layout_width="163.33dp"android:layout_height="40dp"android:layout_marginBottom="30dp"android:gravity="center"android:layout_toRightOf="@id/tv_cancel"android:background="@drawable/selector_sure"android:text="确定"android:textColor="#333333"android:textSize="16sp"/></RelativeLayout>
</RelativeLayout>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:focusable="true"android:focusableInTouchMode="true"android:layout_height="48dp" ><EditTextandroid:id="@+id/search_et"android:layout_width="0dp"android:layout_height="35dp"android:layout_gravity="center_vertical"android:layout_marginLeft="10dp"android:layout_marginRight="10dp"android:layout_weight="1"android:background="@drawable/search_bg"android:drawableLeft="@drawable/image_search" /><CheckBoxandroid:id="@+id/select_all_cb"android:layout_width="48dp"android:layout_height="35dp"android:layout_alignParentRight="true"android:layout_gravity="center_vertical"android:background="@drawable/search_bg"android:button="@null"android:gravity="center"android:text="全选" /><Buttonandroid:id="@+id/import_contacts"android:layout_marginLeft="10dp"android:layout_marginRight="10dp"android:layout_width="48dp"android:layout_height="35dp"android:layout_gravity="center_vertical"android:background="@drawable/search_bg"android:text="导入" ></Button></LinearLayout>
首先看数据库、实体类、工具类代码
MyApplication
package com.example.contactslistview;
import android.app.Application;
public class MyApplication extends Application{ private static MyApplication instance; @Override public void onCreate() { super.onCreate(); this.instance = this; } public static MyApplication getInstance(){ return instance; }
}
DataBaseHelper创建数据库
package com.example.contactslistview.db; import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;public class DataBaseHelper extends SQLiteOpenHelper { /** * 数据库名字 */ private static final String DATABASE_NAME = "geek_saf.db"; /** * 学生信息表名 */ public static final String TABLE_NAME_CONTACT = "contacts"; private static int version = 1; // 构造器 public DataBaseHelper(Context context) { super(context, DATABASE_NAME, null, version); } @Override public void onCreate(SQLiteDatabase db) { createTables(db); } void createTables(SQLiteDatabase db) { String sql = "CREATE TABLE IF NOT EXISTS " + TABLE_NAME_CONTACT + " (" + BaseColum.ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " + BaseColum.NAME + " TEXT, " + BaseColum.PHONE+ " TEXT, " + BaseColum.SORT_KEY+ " TEXT, " + BaseColum.PHOTO_BYTE+ " blob, " + BaseColum.CONTACT_ID + " LONG" + ")"; db.execSQL(sql); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { } /** * 学生信息表字段名 * */ static class BaseColum { public static final String ID = "id"; public static final String CONTACT_ID = "contactId"; public static final String NAME = "name"; public static final String PHONE = "phone"; public static final String PHOTO_BYTE = "photoByte"; public static final String SORT_KEY = "sortKey"; }
}
ContactSqliteManager操作数据库的方法
package com.example.contactslistview.db;import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;import android.R.string;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.provider.ContactsContract;
import android.util.Log;import com.example.contactslistview.MyApplication;
import com.example.contactslistview.bean.CharacterParser;
import com.example.contactslistview.bean.ContactInfo;
import com.example.contactslistview.bean.LogUtils;
import com.example.contactslistview.bean.Pycomparator;
import com.example.contactslistview.db.DataBaseHelper.BaseColum;public class ContactSqliteManager {private DataBaseHelper mDataBaseHelper;private SQLiteDatabase mSQLitedb;private static ContactSqliteManager mInstance;// private long insert;public static ContactSqliteManager getInstance() {if (null == mInstance) {synchronized (ContactSqliteManager.class) {if (null == mInstance) {mInstance = new ContactSqliteManager();}}}return mInstance;}private ContactSqliteManager() {super();if (mSQLitedb == null) {openDataBase(MyApplication.getInstance());}}private void openDataBase(Context context) {if (mDataBaseHelper == null) {mDataBaseHelper = new DataBaseHelper(context);}if (mSQLitedb == null) {mSQLitedb = mDataBaseHelper.getWritableDatabase();}}public static ArrayList<Cursor> listsCursor = new ArrayList<Cursor>();/*** 从数据库中获取联系人 static class BaseColum { public static final String ID = "id";* public static final String CONTACT_ID = "contactId"; public static final* String NAME = "name"; public static final String PHONE = "phone"; public* static final String PHOTO_BYTE = "photoByte"; public static final String* SORT_KEY = "sortKey"; s*/public ArrayList<ContactInfo> getContactsFromInternal() {Cursor internalContactsCursor = null;ArrayList<String> contactPhones = new ArrayList<String>();ArrayList<ContactInfo> listsContacts = new ArrayList<ContactInfo>();ContactInfo contactInfo = null;try {long oldContactId = -1;internalContactsCursor = mSQLitedb.query(DataBaseHelper.TABLE_NAME_CONTACT, null, null, null, null,null, BaseColum.CONTACT_ID);listsCursor.add(internalContactsCursor);if (internalContactsCursor != null&& internalContactsCursor.getCount() > 0) {while (internalContactsCursor.moveToNext()) {String name = internalContactsCursor.getString(internalContactsCursor.getColumnIndex(BaseColum.NAME));String sortKey = internalContactsCursor.getString(internalContactsCursor.getColumnIndex(BaseColum.SORT_KEY));long contactId = internalContactsCursor.getLong(internalContactsCursor.getColumnIndex(BaseColum.CONTACT_ID));String number = internalContactsCursor.getString(internalContactsCursor.getColumnIndex(BaseColum.PHONE));byte[] photoByte = internalContactsCursor.getBlob(internalContactsCursor.getColumnIndex(BaseColum.PHOTO_BYTE));if (contactId == oldContactId) {contactPhones.add(number);contactInfo.setPhones(contactPhones);continue;} else {contactInfo = new ContactInfo();listsContacts.add(contactInfo);contactPhones = new ArrayList<String>();contactPhones.add(number);}// LogUtils.i("ContactsManager", "name:" + name +// ",sortKey:" + sortKey + ",contactId:" + contactId// +",number:"+number+",note:"+note);contactInfo.setSortKey(sortKey);contactInfo.setPhones(contactPhones);contactInfo.setContactName(name);contactInfo.setContactId(contactId);contactInfo.setPhotoByte(photoByte);oldContactId = contactId;}}if (listsContacts != null)Collections.sort(listsContacts, new Pycomparator());} catch (Exception e) {e.printStackTrace();} finally {if (internalContactsCursor != null) {internalContactsCursor.close();}}return listsContacts;}/*** 插入数据 插入所有列* * public static final String ID = "id"; public static final String* CONTACT_ID = "contactId"; public static final String NAME = "name";* public static final String PHONE = "phone"; public static final String* PHOTO_BYTE = "photoByte";*/public long insertContact(ContactInfo contactInfo) {long insertCount = 0;// 准备数据ArrayList<String> contactPhones = contactInfo.getPhones();if (contactPhones != null && contactPhones.size() > 0) {for (int i = 0; i < contactPhones.size(); i++) {ContentValues values = new ContentValues();values.put(BaseColum.NAME, contactInfo.getContactName());values.put(BaseColum.PHONE, contactPhones.get(i));values.put(BaseColum.CONTACT_ID, contactInfo.getContactId());values.put(BaseColum.PHOTO_BYTE, contactInfo.getPhotoByte());values.put(BaseColum.SORT_KEY, contactInfo.getSortKey());mSQLitedb.insert(DataBaseHelper.TABLE_NAME_CONTACT, null,values);values.clear();}}boolean contactInfoIsExist = contactInfoIsExist(contactInfo);if (contactInfoIsExist) {Log.i("ContactSqliteManager", "contactInfoIsExist:");} else {Log.i("ContactSqliteManager", "contactInfoIsExist not");}insertCount = contactInfoIsExist == true ? 1 : 0;return insertCount;}public boolean contactInfoIsExist(ContactInfo contactInfo) {Log.i("ContactSqliteManager", "contactInfoIsExist 导入的记录");boolean contactInfoIsExist = false;String selection = BaseColum.CONTACT_ID + "=?";String[] selectionArgs = new String[] { String.valueOf(contactInfo.getContactId()) };Cursor contactInfoIsExistCursor = mSQLitedb.query(DataBaseHelper.TABLE_NAME_CONTACT, null, selection,selectionArgs, null, null, null);if (contactInfoIsExistCursor != null&& contactInfoIsExistCursor.getCount() > 0) {Log.i("ContactSqliteManager", "contactInfoIsExistCursor != null");if (contactInfoIsExistCursor.moveToFirst()) {Log.i("ContactSqliteManager", "导入的记录,存在");contactInfoIsExist = true;return contactInfoIsExist;} else {Log.i("ContactSqliteManager", "导入的记录,不存在");contactInfoIsExist = false;return contactInfoIsExist;}} else {Log.i("ContactSqliteManager", "contactInfoIsExistCursor == null");}return contactInfoIsExist;}/*** 删除联系人*/public void deleContact(ContactInfo contactInfo) {String whereClause = BaseColum.CONTACT_ID + "=?";String[] whereArgs = new String[] { String.valueOf(contactInfo.getContactId()) };int deleteCount = mSQLitedb.delete(DataBaseHelper.TABLE_NAME_CONTACT,whereClause, whereArgs);Log.i("ContactSqliteManager", "deleteCount:" + deleteCount);}}
ContactInfo实体类
package com.example.contactslistview.bean;import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;import android.graphics.Bitmap;public class ContactInfo {//idprivate long contactId;//姓名private String contactName;//电话数量private ArrayList<String> phones = new ArrayList<String>();//头像byte数组private byte[] photoByte;//用于排序private String sortKey;//是否被选中private boolean isCheck;public long getContactId() {return contactId;}public void setContactId(long contactId) {this.contactId = contactId;}public String getContactName() {return contactName;}public void setContactName(String contactName) {this.contactName = contactName;}public ArrayList<String> getPhones() {return phones;}public void setPhones(ArrayList<String> phones) {this.phones = phones;}public String getSortKey() {return sortKey;}public void setSortKey(String sortKey) {this.sortKey = sortKey;}public boolean isCheck() {return isCheck;}public void setCheck(boolean isCheck) {this.isCheck = isCheck;}public byte[] getPhotoByte() {return photoByte;}public void setPhotoByte(byte[] photoByte) {this.photoByte = photoByte;}public ContactInfo(long contactId, String contactName,ArrayList<String> phones, String sortKey, boolean isCheck,byte[] photoByte) {super();this.contactId = contactId;this.contactName = contactName;this.phones = phones;this.sortKey = sortKey;this.isCheck = isCheck;this.photoByte = photoByte;}public ContactInfo() {super();}}
LogUtils工具类
package com.example.contactslistview.bean;import android.util.Log;public class LogUtils {private static final String HEAD_TAG = "GLauncher_";public static void v(Class<?> clazz,String logInfo){i(clazz.getSimpleName(),logInfo);}public static void v(String tag,String logInfo){printLogInfo(tag,logInfo,Log.VERBOSE);} public static void i(Class<?> clazz,String logInfo){i(clazz.getSimpleName(),logInfo);}public static void i(String tag,String logInfo){printLogInfo(tag,logInfo,Log.INFO);} public static void d(Class<?> clazz,String logInfo){d(clazz.getSimpleName(),logInfo);}public static void d(String tag,String logInfo){printLogInfo(tag,logInfo,Log.DEBUG);}public static void w(Class<?> clazz,String logInfo){w(clazz.getSimpleName(),logInfo);}public static void w(String tag,String logInfo){printLogInfo(tag,logInfo,Log.WARN);}public static void e(Class<?> clazz,String logInfo){e(clazz.getSimpleName(),logInfo);}public static void e(String tag,String logInfo){printLogInfo(tag,logInfo,Log.ERROR);}public static void printLogInfo(String tag,String logInfo,int style){switch (style) {case Log.VERBOSE:Log.v(HEAD_TAG + tag,logInfo);break;case Log.INFO:Log.i(HEAD_TAG + tag,logInfo);break;case Log.DEBUG:Log.d(HEAD_TAG + tag,logInfo);break;case Log.ERROR:Log.e(HEAD_TAG + tag,logInfo);break;case Log.WARN:Log.w(HEAD_TAG + tag,logInfo);break;}}
}
Pycomparator排序的类
package com.example.contactslistview.bean;import java.util.ArrayList;
import java.util.Comparator;import android.text.TextUtils;/*** Created by Administrator on 2016/4/14.*/
public class Pycomparator implements Comparator<ContactInfo> {@Overridepublic int compare(ContactInfo contact1, ContactInfo contact2) {String name1=contact1.getSortKey();String name2=contact2.getSortKey();if (TextUtils.isEmpty(name1)){ArrayList<String> contactPhones= (ArrayList<String>) contact1.getPhones();if (contactPhones!=null&&contactPhones.size()>0)name1=contactPhones.get(0);}if (TextUtils.isEmpty(name2)){ArrayList<String> contactPhones= (ArrayList<String>) contact2.getPhones();if (contactPhones!=null&&contactPhones.size()>0){name2=contactPhones.get(0);}}if (!TextUtils.isEmpty(name1)&&!TextUtils.isEmpty(name2)){boolean firstisChar=false;boolean secondisChar=false;if (((name1.charAt(0)>='a'&&name1.charAt(0)<='z'))||(name1.charAt(0)>='A'&&name1.charAt(0)<='Z'))firstisChar=true;if (((name2.charAt(0)>='a'&&name2.charAt(0)<='z'))||(name2.charAt(0)>='A'&&name2.charAt(0)<='Z'))secondisChar=true;if (firstisChar&&secondisChar){return name1.compareToIgnoreCase(name2);}else if (firstisChar&&!secondisChar){return -1;}else if (!firstisChar&&secondisChar){return 1;}else{return name1.compareToIgnoreCase(name2);}}return 0;}
}
CharacterParser词语解析类
package com.example.contactslistview.bean;/*** Created by Administrator on 2016/4/14.*/
public class CharacterParser {private static int[] pyvalue = new int[] {-20319, -20317, -20304, -20295, -20292, -20283, -20265, -20257, -20242, -20230, -20051, -20036, -20032,-20026, -20002, -19990, -19986, -19982, -19976, -19805, -19784, -19775, -19774, -19763, -19756, -19751, -19746, -19741, -19739, -19728,-19725, -19715, -19540, -19531, -19525, -19515, -19500, -19484, -19479, -19467, -19289, -19288, -19281, -19275, -19270, -19263, -19261,-19249, -19243, -19242, -19238, -19235, -19227, -19224, -19218, -19212, -19038, -19023, -19018, -19006, -19003, -18996, -18977, -18961,-18952, -18783, -18774, -18773, -18763, -18756, -18741, -18735, -18731, -18722, -18710, -18697, -18696, -18526, -18518, -18501, -18490,-18478, -18463, -18448, -18447, -18446, -18239, -18237, -18231, -18220, -18211, -18201, -18184, -18183, -18181, -18012, -17997, -17988,-17970, -17964, -17961, -17950, -17947, -17931, -17928, -17922, -17759, -17752, -17733, -17730, -17721, -17703, -17701, -17697, -17692,-17683, -17676, -17496, -17487, -17482, -17468, -17454, -17433, -17427, -17417, -17202, -17185, -16983, -16970, -16942, -16915, -16733,-16708, -16706, -16689, -16664, -16657, -16647, -16474, -16470, -16465, -16459, -16452, -16448, -16433, -16429, -16427, -16423, -16419,-16412, -16407, -16403, -16401, -16393, -16220, -16216, -16212, -16205, -16202, -16187, -16180, -16171, -16169, -16158, -16155, -15959,-15958, -15944, -15933, -15920, -15915, -15903, -15889, -15878, -15707, -15701, -15681, -15667, -15661, -15659, -15652, -15640, -15631,-15625, -15454, -15448, -15436, -15435, -15419, -15416, -15408, -15394, -15385, -15377, -15375, -15369, -15363, -15362, -15183, -15180,-15165, -15158, -15153, -15150, -15149, -15144, -15143, -15141, -15140, -15139, -15128, -15121, -15119, -15117, -15110, -15109, -14941,-14937, -14933, -14930, -14929, -14928, -14926, -14922, -14921, -14914, -14908, -14902, -14894, -14889, -14882, -14873, -14871, -14857,-14678, -14674, -14670, -14668, -14663, -14654, -14645, -14630, -14594, -14429, -14407, -14399, -14384, -14379, -14368, -14355, -14353,-14345, -14170, -14159, -14151, -14149, -14145, -14140, -14137, -14135, -14125, -14123, -14122, -14112, -14109, -14099, -14097, -14094,-14092, -14090, -14087, -14083, -13917, -13914, -13910, -13907, -13906, -13905, -13896, -13894, -13878, -13870, -13859, -13847, -13831,-13658, -13611, -13601, -13406, -13404, -13400, -13398, -13395, -13391, -13387, -13383, -13367, -13359, -13356, -13343, -13340, -13329,-13326, -13318, -13147, -13138, -13120, -13107, -13096, -13095, -13091, -13076, -13068, -13063, -13060, -12888, -12875, -12871, -12860,-12858, -12852, -12849, -12838, -12831, -12829, -12812, -12802, -12607, -12597, -12594, -12585, -12556, -12359, -12346, -12320, -12300,-12120, -12099, -12089, -12074, -12067, -12058, -12039, -11867, -11861, -11847, -11831, -11798, -11781, -11604, -11589, -11536, -11358,-11340, -11339, -11324, -11303, -11097, -11077, -11067, -11055, -11052, -11045, -11041, -11038, -11024, -11020, -11019, -11018, -11014,-10838, -10832, -10815, -10800, -10790, -10780, -10764, -10587, -10544, -10533, -10519, -10331, -10329, -10328, -10322, -10315, -10309,-10307, -10296, -10281, -10274, -10270, -10262, -10260, -10256, -10254};public static String[] pystr = new String[] {"a", "ai", "an", "ang", "ao", "ba", "bai", "ban", "bang", "bao", "bei", "ben", "beng", "bi", "bian","biao", "bie", "bin", "bing", "bo", "bu", "ca", "cai", "can", "cang", "cao", "ce", "ceng", "cha", "chai", "chan", "chang", "chao", "che","chen", "cheng", "chi", "chong", "chou", "chu", "chuai", "chuan", "chuang", "chui", "chun", "chuo", "ci", "cong", "cou", "cu", "cuan","cui", "cun", "cuo", "da", "dai", "dan", "dang", "dao", "de", "deng", "di", "dian", "diao", "die", "ding", "diu", "dong", "dou", "du","duan", "dui", "dun", "duo", "e", "en", "er", "fa", "fan", "fang", "fei", "fen", "feng", "fo", "fou", "fu", "ga", "gai", "gan", "gang","gao", "ge", "gei", "gen", "geng", "gong", "gou", "gu", "gua", "guai", "guan", "guang", "gui", "gun", "guo", "ha", "hai", "han", "hang","hao", "he", "hei", "hen", "heng", "hong", "hou", "hu", "hua", "huai", "huan", "huang", "hui", "hun", "huo", "ji", "jia", "jian","jiang", "jiao", "jie", "jin", "jing", "jiong", "jiu", "ju", "juan", "jue", "jun", "ka", "kai", "kan", "kang", "kao", "ke", "ken","keng", "kong", "kou", "ku", "kua", "kuai", "kuan", "kuang", "kui", "kun", "kuo", "la", "lai", "lan", "lang", "lao", "le", "lei", "leng","li", "lia", "lian", "liang", "liao", "lie", "lin", "ling", "liu", "long", "lou", "lu", "lv", "luan", "lue", "lun", "luo", "ma", "mai","man", "mang", "mao", "me", "mei", "men", "meng", "mi", "mian", "miao", "mie", "min", "ming", "miu", "mo", "mou", "mu", "na", "nai","nan", "nang", "nao", "ne", "nei", "nen", "neng", "ni", "nian", "niang", "niao", "nie", "nin", "ning", "niu", "nong", "nu", "nv", "nuan","nue", "nuo", "o", "ou", "pa", "pai", "pan", "pang", "pao", "pei", "pen", "peng", "pi", "pian", "piao", "pie", "pin", "ping", "po", "pu","qi", "qia", "qian", "qiang", "qiao", "qie", "qin", "qing", "qiong", "qiu", "qu", "quan", "que", "qun", "ran", "rang", "rao", "re","ren", "reng", "ri", "rong", "rou", "ru", "ruan", "rui", "run", "ruo", "sa", "sai", "san", "sang", "sao", "se", "sen", "seng", "sha","shai", "shan", "shang", "shao", "she", "shen", "sheng", "shi", "shou", "shu", "shua", "shuai", "shuan", "shuang", "shui", "shun","shuo", "si", "song", "sou", "su", "suan", "sui", "sun", "suo", "ta", "tai", "tan", "tang", "tao", "te", "teng", "ti", "tian", "tiao","tie", "ting", "tong", "tou", "tu", "tuan", "tui", "tun", "tuo", "wa", "wai", "wan", "wang", "wei", "wen", "weng", "wo", "wu", "xi","xia", "xian", "xiang", "xiao", "xie", "xin", "xing", "xiong", "xiu", "xu", "xuan", "xue", "xun", "ya", "yan", "yang", "yao", "ye", "yi","yin", "ying", "yo", "yong", "you", "yu", "yuan", "yue", "yun", "za", "zai", "zan", "zang", "zao", "ze", "zei", "zen", "zeng", "zha","zhai", "zhan", "zhang", "zhao", "zhe", "zhen", "zheng", "zhi", "zhong", "zhou", "zhu", "zhua", "zhuai", "zhuan", "zhuang", "zhui","zhun", "zhuo", "zi", "zong", "zou", "zu", "zuan", "zui", "zun", "zuo"};private String resource;private static CharacterParser characterParser = new CharacterParser();public static CharacterParser getInstance() {return characterParser;}public String getResource() {return resource;}public void setResource(String resource) {this.resource = resource;}/** * 汉字转成ASCII码 * * @param chs * @return */private int getChsAscii(String chs) {int asc = 0;try {byte[] bytes = chs.getBytes("gb2312");if (bytes == null || bytes.length > 2 || bytes.length <= 0) {throw new RuntimeException("illegal resource string");}if (bytes.length == 1) {asc = bytes[0];}if (bytes.length == 2) {int hightByte = 256 + bytes[0];int lowByte = 256 + bytes[1];asc = (256 * hightByte + lowByte) - 256 * 256;}} catch (Exception e) {System.out.println("ERROR:ChineseSpelling.class-getChsAscii(String chs)" + e);}return asc;}/** * 单字解析 * * @param str * @return */public String convert(String str) {String result = null;int ascii = getChsAscii(str);if (ascii > 0 && ascii < 160) {result = String.valueOf((char) ascii);} else {for (int i = (pyvalue.length - 1); i >= 0; i--) {if (pyvalue[i] <= ascii) {result = pystr[i];break;}}}return result;}/** * 词组解析 * * @param chs * @return */public String getSelling(String chs) {String key, value;StringBuilder buffer = new StringBuilder();for (int i = 0; i < chs.length(); i++) {key = chs.substring(i, i + 1);if (key.getBytes().length >= 2) {value = convert(key);if (value == null) {value = "unknown";}} else {value = key;}buffer.append(value);}return buffer.toString();}public String getSpelling() {return this.getSelling(this.getResource());}
}
ContactsManager系统联系人的操作方法
package com.example.contactslistview.contactmanager;import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;import android.content.ContentResolver;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.provider.ContactsContract;import com.example.contactslistview.bean.CharacterParser;
import com.example.contactslistview.bean.ContactInfo;
import com.example.contactslistview.bean.LogUtils;
import com.example.contactslistview.bean.Pycomparator;public class ContactsManager {private ContentResolver mContentResolver;private static ContactsManager contactsManager;private ContactsManager(Context mContext) {super();mContentResolver = mContext.getContentResolver();}public static ContactsManager getInstance(Context mContext) {ContactsManager contactsManager = null;if (contactsManager == null) {contactsManager = new ContactsManager(mContext);}return contactsManager;}public static ArrayList<Cursor> listsCursor=new ArrayList<Cursor>();//获取联系人的信息并排序public ArrayList<ContactInfo> getLocalContacts() {Cursor contactsCursor=null;ArrayList<String> contactPhones = new ArrayList<String>();//构建集合ArrayList<ContactInfo> listsContacts = new ArrayList<ContactInfo>();//构建对象ContactInfo contactInfo = null;try{long oldContactId = -1;/**public static final Uri CONTENT_URI = Uri.withAppendedPath(Data.CONTENT_URI,"phones");* uri=content://com.android.contacts/data/phones*/Uri uri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;String[] projection = {ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME,ContactsContract.CommonDataKinds.Phone.SORT_KEY_PRIMARY,ContactsContract.CommonDataKinds.Phone.CONTACT_ID,ContactsContract.CommonDataKinds.Phone.NUMBER};contactsCursor = mContentResolver.query(uri, projection, null, null,ContactsContract.CommonDataKinds.Phone.CONTACT_ID);//默认升序listsCursor.add(contactsCursor);if (contactsCursor != null && contactsCursor.getCount() > 0) {while (contactsCursor.moveToNext()) {//nameString name = contactsCursor.getString(contactsCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));//跟name一样String sort_key = contactsCursor.getString(contactsCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.SORT_KEY_PRIMARY));String fullspell = sort_key;//如果某个联系人的第一个字符不是汉字,就转为全拼,第一个是字母的,不用操作if (isChinese(sort_key.charAt(0))) {fullspell = CharacterParser.getInstance().getSelling(sort_key);}//获取联系人姓名全拼的第一个字母-sortKeyString sortKey = getSortKey(fullspell);LogUtils.i("ContactsManager", "sortKey:"+sortKey);long contactId = contactsCursor.getLong(contactsCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.CONTACT_ID));String number = contactsCursor.getString(contactsCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));if (contactId == oldContactId) {contactPhones.add(number);contactInfo.setPhones(contactPhones);continue;} else {contactInfo = new ContactInfo();listsContacts.add(contactInfo);contactPhones = new ArrayList<String>();contactPhones.add(number);}/** 头像*/Uri photoUri = Uri.parse("content://com.android.contacts/contacts/" + contactId);InputStream input = ContactsContract.Contacts.openContactPhotoInputStream(mContentResolver, photoUri);byte[] photoByte = null;if (input!=null){photoByte = toByteArray(input);contactInfo.setPhotoByte(photoByte);}LogUtils.i("ContactsManager", "name:" + name + ",sortKey:" + sortKey +",contactId:" + contactId+",number:"+number+",photoByte:"+photoByte);contactInfo.setSortKey(sortKey);contactInfo.setPhones(contactPhones);contactInfo.setContactName(name);contactInfo.setContactId(contactId);contactInfo.setPhotoByte(photoByte);oldContactId = contactId;}}if (listsContacts != null)Collections.sort(listsContacts, new Pycomparator());}catch (Exception e){LogUtils.i("ContactsManager", "Exception");e.printStackTrace();}finally {if (contactsCursor!=null){System.out.println("close cursor");contactsCursor.close();}}return listsContacts;}/*** input转为二进制* @param input* @return* @throws IOException*/public byte[] toByteArray(InputStream input) throws IOException {ByteArrayOutputStream output = new ByteArrayOutputStream();byte[] buffer = new byte[4096];int n = 0;while (-1 != (n = input.read(buffer))) {output.write(buffer, 0, n);}return output.toByteArray();}private String getSortKey(String sortKey) {String key = sortKey.substring(0, 1).toUpperCase();if (key.matches("[A-Z]")) {return key;}return "#";}//应该是匹配一个或以上的汉字private boolean isChinese(char a) {return String.valueOf(a).matches("[\u4E00-\u9FA5]");}}
接下来看主界面的代码
MainActivity
package com.example.contactslistview;import java.util.ArrayList;
import java.util.Collections;import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;import com.example.contactslistview.bean.CharacterParser;
import com.example.contactslistview.bean.ContactInfo;
import com.example.contactslistview.bean.ImportingDialog;
import com.example.contactslistview.bean.LogUtils;
import com.example.contactslistview.bean.Pycomparator;
import com.example.contactslistview.bean.QuickAlphabeticBar;
import com.example.contactslistview.contactmanager.ContactsManager;
import com.example.contactslistview.contactmanager.GLauncherExectorManger;
import com.example.contactslistview.db.ContactSqliteManager;public class MainActivity extends Activity implements OnClickListener {private String LOG_TAG = "MainActivity";private CheckBox select_all_cb;private EditText search_et;private ListView mListView;private QuickAlphabeticBar alphabeticBar;private Button import_contacts;private ArrayList<ContactInfo> contactsFromInternal;private ContactsListAdapter contactAdapter;private ImportingDialog importingDialog = null;private RelativeLayout ll_button;private TextView tv_cancel, tv_sure;private int importSum;private ArrayList<ContactInfo> filterListsContact = new ArrayList<ContactInfo>();private SharedPreferences sharedPreferences;private Handler updateUiHandler = new Handler() {public void handleMessage(android.os.Message msg) {if (msg.what == 0) {LogUtils.i(LOG_TAG, "contactsFromInternal.size-->>"+ contactsFromInternal.size());contactAdapter = new ContactsListAdapter(MainActivity.this,contactsFromInternal, alphabeticBar, false);mListView.setAdapter(contactAdapter);mListView.setDividerHeight(0);// 初始化字母条alphabeticBar.init(MainActivity.this);alphabeticBar.setListView(mListView);alphabeticBar.setVisibility(View.VISIBLE);}};};private void initRes() {sharedPreferences = getSharedPreferences("Safly", Context.MODE_PRIVATE);ll_button = (RelativeLayout) findViewById(R.id.ll_button);tv_cancel = (TextView) findViewById(R.id.tv_cancel);tv_sure = (TextView) findViewById(R.id.tv_sure);tv_cancel.setOnClickListener(this);tv_sure.setOnClickListener(this);select_all_cb = (CheckBox) findViewById(R.id.select_all_cb);select_all_cb.setVisibility(View.GONE);search_et = (EditText) findViewById(R.id.search_et);mListView = (ListView) findViewById(R.id.mListView);importingDialog = new ImportingDialog(MainActivity.this);importingDialog.setCanceledOnTouchOutside(false);alphabeticBar = (QuickAlphabeticBar) findViewById(R.id.contact_list_fast_scroller);alphabeticBar.init(this);alphabeticBar.setListView(mListView);alphabeticBar.setVisibility(View.VISIBLE);import_contacts = (Button) findViewById(R.id.import_contacts);import_contacts.setOnClickListener(this);if(sharedPreferences.getBoolean("isImport", false))import_contacts.setVisibility(View.GONE);elseimport_contacts.setVisibility(View.VISIBLE);select_all_cb.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {if (select_all_cb.isChecked()) {LogUtils.i(LOG_TAG, "isChecked true");contactAdapter.initSelectedState(true);contactAdapter.notifyDataSetChanged();} else {LogUtils.i(LOG_TAG, "isChecked false");contactAdapter.initSelectedState(false);contactAdapter.notifyDataSetChanged();}}});}@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.activity_main);initRes();GLauncherExectorManger.getInstance().addTask(new Runnable() {@Overridepublic void run() {contactsFromInternal = ContactSqliteManager.getInstance().getContactsFromInternal();updateUiHandler.sendEmptyMessage(0);}});mListView.setOnItemLongClickListener(new OnItemLongClickListener() {@Overridepublic boolean onItemLongClick(AdapterView<?> parent, View view,int position, long id) {LogUtils.i(LOG_TAG, "onItemLongClick");select_all_cb.setVisibility(View.VISIBLE);Animation animation = AnimationUtils.loadAnimation(MainActivity.this, R.drawable.delete_btn_anim);animation.setAnimationListener(new Animation.AnimationListener() {@Overridepublic void onAnimationStart(Animation animation) {}@Overridepublic void onAnimationRepeat(Animation animation) {}@Overridepublic void onAnimationEnd(Animation animation) {mListView.setPadding(0, 0, 0, dip2px(100));}});ll_button.startAnimation(animation);ll_button.setVisibility(View.VISIBLE);contactAdapter.updataMultiChoice();return false;}});/*** 搜索联系人*/search_et.addTextChangedListener(new TextWatcher() {@Overridepublic void beforeTextChanged(CharSequence s, int start, int count,int after) {}@Overridepublic void onTextChanged(CharSequence s, int start, int before,int count) {filterContacts(s.toString());}@Overridepublic void afterTextChanged(Editable s) {}});}private void filterContacts(String filter) {filterListsContact.clear();if (TextUtils.isEmpty(filter)) {filterListsContact.addAll(contactsFromInternal);} else {for (ContactInfo member : contactsFromInternal) {/** 如果contactName第一个字符是汉文 */if (isChinese(member.getContactName().charAt(0))) {if (isChinese(filter.charAt(0))) {// 如果搜索引擎第一个字符是汉文if (member.getContactName().startsWith(filter))filterListsContact.add(member);} else {// 如果不是用中文来搜索--获取contactName的全拼音if (isNameAndFilterEqual(CharacterParser.getInstance().getSelling(member.getContactName()), filter))filterListsContact.add(member);}} else {/** 如果contactName第一个字符不是汉文 */if (isNameAndFilterEqual(member.getContactName(), filter))filterListsContact.add(member);}}}Collections.sort(filterListsContact, new Pycomparator());contactAdapter.updateListView(filterListsContact);}/*** @param contactName* @param filter* @return*/private boolean isNameAndFilterEqual(String contactName, String filter) {for (int i = 0; i < filter.length(); i++) {if (!(contactName.charAt(i) == filter.charAt(i) || convertLowerAndUpper(contactName.charAt(i)) == filter.charAt(i)))return false;}return true;}/*** 转换大小写* * @param ch* @return*/private char convertLowerAndUpper(char ch) {if (ch >= 'a' && ch <= 'z')return String.valueOf(ch).toUpperCase().charAt(0);elsereturn String.valueOf(ch).toLowerCase().charAt(0);}private boolean isChinese(char a) {return String.valueOf(a).matches("[\u4E00-\u9FA5]");}public CheckBox getSelectAll() {return select_all_cb;}public TextView getTvSure() {return tv_sure;}public int dip2px(float dipValue) {final float scale = getResources().getDisplayMetrics().density;return (int) (dipValue * scale + 0.5f);}@Overridepublic void onClick(View v) {switch (v.getId()) {case R.id.import_contacts:// 导入联系人,插入数据库final ArrayList<ContactInfo> localContacts = ContactsManager.getInstance(MainActivity.this).getLocalContacts();if (localContacts != null && localContacts.size() > 0) {importingDialog.show();importingDialog.initViewBeforeShow(localContacts.size());LogUtils.i(LOG_TAG,"localContacts.size()-->>" + localContacts.size());new AsyncTask<Void, Integer, Void>() {@Overrideprotected Void doInBackground(Void... params) {// 循环的是需要导进来的联系人--实际开发中需要判断是否重复导入for (ContactInfo contactInfo : localContacts) {LogUtils.i(LOG_TAG,"contactInfo:getContactId:"+ contactInfo.getContactId()+ ",getContactName:"+ contactInfo.getContactName());importSum += ContactSqliteManager.getInstance().insertContact(contactInfo);try {Thread.sleep(800);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}publishProgress(importSum);}return null;}@Overrideprotected void onProgressUpdate(Integer... values) {// importCountimportingDialog.notifyByteProgress(localContacts.size(), values[0]);}@Overrideprotected void onPostExecute(Void aVoid) {importingDialog.setCanceledOnTouchOutside(true);if (importSum == localContacts.size()) {if (importingDialog.isShowing()) {LogUtils.i(LOG_TAG, "importSum success:"+ importSum + ",localContacts:"+ localContacts.size());importingDialog.onComplete();if (importingDialog.isShowing()) {importingDialog.dismiss();}sharedPreferences.edit().putBoolean("isImport", true).commit();import_contacts.setVisibility(View.GONE);/*** 导入联系人后,更新ui界面*/GLauncherExectorManger.getInstance().addTask(new Runnable() {@Overridepublic void run() {contactsFromInternal = ContactSqliteManager.getInstance().getContactsFromInternal();updateUiHandler.sendEmptyMessage(0);}});}} else {LogUtils.i(LOG_TAG, "importSum fail:" + importSum+ ",localContacts:" + localContacts.size());importingDialog.onFailed();}}}.execute();} else {Toast.makeText(MainActivity.this, "没有联系人可导入",Toast.LENGTH_SHORT).show();}break;case R.id.tv_cancel:break;case R.id.tv_sure:break;default:break;}}
}
从系统手机获取联系人的线程池优化
package com.example.contactslistview.contactmanager;import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;import android.content.Context;public class GLauncherExectorManger {private static ExecutorService exector = null;private static GLauncherExectorManger instance;private GLauncherExectorManger() {exector = Executors.newFixedThreadPool(4,new ExecutorThreadFactory());}public static GLauncherExectorManger getInstance() {GLauncherExectorManger instance = null;if (instance == null) {instance = new GLauncherExectorManger();}return instance;}/*** 添加一个任务* * @param runnable*/public void addTask(Runnable runnable) {exector.execute(runnable);}/*** 自定义的ThreadFactory工厂,增加对线程创建与销毁等更多的控制*/public class ExecutorThreadFactory implements ThreadFactory{private final AtomicInteger mCount = new AtomicInteger(1);@Overridepublic Thread newThread(Runnable r) {Thread thread = new Thread(r,"GLauncherThread:"+mCount.getAndIncrement());thread.setPriority(Thread.NORM_PRIORITY -1);return thread;}}}
看适配器的代码ContactsListAdapter
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"android:layout_width="match_parent"android:layout_height="match_parent"android:background="#e6e6e6"android:descendantFocusability="blocksDescendants"android:orientation="vertical" ><RelativeLayoutandroid:id="@+id/relative_contact_list_item_alpha"android:layout_width="match_parent"android:layout_height="wrap_content"><Viewandroid:id="@+id/view_line_top"android:layout_width="match_parent"android:layout_height="1px"android:background="@drawable/line"android:visibility="visible" /><RelativeLayoutandroid:id="@+id/ll_contact_list_item_alpha"android:layout_width="fill_parent"android:layout_height="40dp" ><TextViewandroid:id="@+id/tv_contact_list_item_alpha"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_centerVertical="true"android:layout_marginLeft="56dp"android:text="A"android:textColor="#666666"android:textSize="16sp"android:typeface="sans" /></RelativeLayout></RelativeLayout><RelativeLayoutandroid:id="@+id/re_item_all"android:layout_width="match_parent"android:layout_height="60dp"android:background="@drawable/selector_row" ><!-- 联系人信息 --><CheckBoxandroid:id="@+id/cb_check"android:layout_width="wrap_content"android:layout_height="60dp"android:button="@drawable/selector_check"android:layout_marginLeft="17dp"android:layout_centerVertical="true"android:focusableInTouchMode="false"/><com.example.contactslistview.bean.RoundImageViewandroid:id="@+id/contactIcon"android:layout_width="33.33dp"android:layout_height="33.33dp"android:layout_toRightOf="@id/cb_check"android:layout_marginLeft="18.777dp"android:layout_centerVertical="true"android:background="@drawable/contact_photo"/><TextViewandroid:id="@+id/tv_name"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="果冻"android:layout_toRightOf="@id/contactIcon"android:layout_centerVertical="true"android:layout_marginLeft="10dp"android:textColor="#111111"android:textSize="16sp"/></RelativeLayout></LinearLayout>
package com.example.contactslistview;import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;import android.content.Context;
import android.graphics.BitmapFactory;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.RelativeLayout;
import android.widget.TextView;import com.example.contactslistview.bean.ContactInfo;
import com.example.contactslistview.bean.LogUtils;
import com.example.contactslistview.bean.QuickAlphabeticBar;
import com.example.contactslistview.bean.RoundImageView;/*** Created by Administrator on 2016/4/13.*/
public class ContactsListAdapter extends BaseAdapter{private static String LOG_TAG=ContactsListAdapter.class.getSimpleName();private LayoutInflater inflater;private Context context;private ArrayList<ContactInfo> listsContact;//String:sortKey Integer:listsContact的角标索引private HashMap<String,Integer> alphaIndexer;//long是contactId boolean是选中情况private HashMap<Long,Boolean> isSelected=new HashMap<Long, Boolean>();//用来控制CheckBox的选中情况private boolean isMultiChoice;//是不是导入联系人//构造函数public ContactsListAdapter(Context context,ArrayList<ContactInfo> listsContact,QuickAlphabeticBar alphabet,boolean isMultiChoice){this.isMultiChoice = isMultiChoice;this.context=context;this.listsContact=listsContact;this.inflater=LayoutInflater.from(context);this.alphaIndexer=new HashMap<String,Integer>();initAlphabeticBar(alphabet);initSelectedState(false);}/*** 获取联系人sortkey的数组* @param alpha*/public void initAlphabeticBar(QuickAlphabeticBar alphabet){alphaIndexer=new HashMap<String,Integer>();for (int i=0;i<listsContact.size();i++){String sortKey=listsContact.get(i).getSortKey();if (!alphaIndexer.containsKey(sortKey)){alphaIndexer.put(sortKey,i);}}alphabet.setEnabled(false);alphabet.setAlphaIndexer(alphaIndexer);}/*** 全选、取消* @param isSelectedAll*/public void initSelectedState(boolean isSelectedAll){isSelected.clear();if (isSelectedAll){for (int i=0;i<listsContact.size();i++){isSelected.put(listsContact.get(i).getContactId(),true);listsContact.get(i).setCheck(true);}}else{for (int i=0;i<listsContact.size();i++){isSelected.put(listsContact.get(i).getContactId(),false);listsContact.get(i).setCheck(false);}}}public void updateListView(ArrayList<ContactInfo> listsContact){this.listsContact=listsContact;notifyDataSetChanged();}public HashMap<Long, Boolean> getIsSelected() {return isSelected;}public ArrayList<ContactInfo> getListsContact() {return listsContact; //返回列表中所有的联系人}/*** 进入多选模式*/public void updataMultiChoice(){LogUtils.i(LOG_TAG, "updataMultiChoice");this.isMultiChoice = true;notifyDataSetChanged();}@Overridepublic int getCount() {return listsContact.size();}@Overridepublic Object getItem(int position) {return listsContact.get(position);}@Overridepublic long getItemId(int position) {return position;}@Overridepublic View getView(final int position, View convertView, ViewGroup parent) {final ViewHolder viewHolder;if (convertView==null){convertView=inflater.inflate(R.layout.contact_dele_list_item,parent,false);viewHolder=new ViewHolder(convertView);convertView.setTag(viewHolder);}else{viewHolder= (ViewHolder) convertView.getTag();}final ContactInfo contact=listsContact.get(position);String name=contact.getContactName();//nameviewHolder.name.setText(name);//photobyte[] iconBytes = contact.getPhotoByte();if(iconBytes != null){viewHolder.photo.setImageBitmap(BitmapFactory.decodeByteArray(iconBytes,0,iconBytes.length));}else{viewHolder.photo.setImageBitmap(BitmapFactory.decodeResource(context.getResources(), R.drawable.contact_photo));}String sortKey=contact.getSortKey();String currentStr=sortKey;String previewStr=position-1>=0?listsContact.get(position-1).getSortKey():"";if (!previewStr.equals(currentStr)){viewHolder.alpha.setVisibility(View.VISIBLE);viewHolder.alpha.setText(currentStr);viewHolder.ll_contact_list_item_alpha.setVisibility(View.VISIBLE);viewHolder.view_line_top.setVisibility(View.GONE);}else{viewHolder.alpha.setVisibility(View.GONE);viewHolder.alpha.setText(null);viewHolder.ll_contact_list_item_alpha.setVisibility(View.GONE);viewHolder.view_line_top.setVisibility(View.VISIBLE);}viewHolder.cb_check.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {@Overridepublic void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {int count = 0;isSelected.put(listsContact.get(position).getContactId(), isChecked);listsContact.get(position).setCheck(getIsSelected().get(listsContact.get(position).getContactId()));if (isSelected.size() > 0) {Iterator<Boolean> iterator = isSelected.values().iterator();while (iterator.hasNext()) {if (iterator.next() == true) {count++;}}if (count > 0) {((MainActivity) context).getTvSure().setEnabled(true);((MainActivity) context).getTvSure().setText("确定(" + count + ")");}else {((MainActivity) context).getTvSure().setEnabled(false);((MainActivity) context).getTvSure().setText("确定");}} if (isSelected.size() == 0) {LogUtils.i(LOG_TAG, "isSelected.size() ==++ 0");((MainActivity) context).getTvSure().setEnabled(false);((MainActivity) context).getTvSure().setText("确定");}if (count==listsContact.size()){((MainActivity) context).getSelectAll().setText("取消");((MainActivity) context).getSelectAll().setChecked(true);}else{((MainActivity) context).getSelectAll().setChecked(false);((MainActivity) context).getSelectAll().setText("全选");}}});if (isMultiChoice) {viewHolder.cb_check.setVisibility(View.VISIBLE);if(getIsSelected()!=null && getIsSelected().size()>0){viewHolder.cb_check.setChecked(getIsSelected().get(listsContact.get(position).getContactId()));}}else {viewHolder.cb_check.setVisibility(View.GONE);}/*** 解决setOnItemLongClickListener 跟setOnClickListener的冲突事件*/if (isMultiChoice) {viewHolder.re_item_all.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {if(viewHolder.cb_check.isChecked()){viewHolder.cb_check.setChecked(false);}else{viewHolder.cb_check.setChecked(true);}}});}return convertView;}class ViewHolder{TextView alpha;RelativeLayout ll_contact_list_item_alpha;CheckBox cb_check;RoundImageView photo;TextView name;RelativeLayout re_item_all;View view_line_top;public ViewHolder(View view){photo = (RoundImageView) view.findViewById(R.id.contactIcon);alpha= (TextView) view.findViewById(R.id.tv_contact_list_item_alpha);view_line_top=view.findViewById(R.id.view_line_top);name= (TextView) view.findViewById(R.id.tv_name);cb_check= (CheckBox) view.findViewById(R.id.cb_check);ll_contact_list_item_alpha= (RelativeLayout) view.findViewById(R.id.ll_contact_list_item_alpha);re_item_all= (RelativeLayout) view.findViewById(R.id.re_item_all);}}}
继续看进度条
ImportingDialog
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical"android:background="@drawable/shape_rect_dialog"android:layout_width="200dp"android:layout_height="133.33dp"><!-- 导入的人数 --><TextViewandroid:id="@+id/tv_person"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="38.67dp"android:layout_centerHorizontal="true"android:textSize="16sp"android:text="2/15"android:textColor="#333333"/><!-- 进度条 --><com.example.contactslistview.bean.CustomProgressBarandroid:id="@+id/progress"android:layout_width="180dip"android:layout_height="10dip"android:layout_below="@id/tv_person"android:layout_centerHorizontal="true"android:layout_marginTop="9.33dp"android:background="@drawable/pro_line"/><!-- 导入的状态 --><TextViewandroid:id="@+id/tv_importing"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_below="@id/progress"android:layout_centerHorizontal="true"android:layout_marginTop="18.33dp"android:text="导入中..."android:textSize="16sp"android:textColor="#555555"/><!-- -导入成功 --><!-- 导入失败图片 --><ImageViewandroid:id="@+id/import_fail"android:layout_width="wrap_content"android:layout_height="wrap_content"android:src="@drawable/anzhuanghsibai"android:visibility="invisible"android:layout_centerInParent="true"/><!-- -导入失败字体 --><TextViewandroid:id="@+id/tv_fail"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_centerHorizontal="true"android:layout_marginTop="20dp"android:text="导入失败"android:textSize="16sp"android:visibility="invisible"android:textColor="#666666"/>
</RelativeLayout>
package com.example.contactslistview.bean;import android.app.Dialog;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.TextView;import com.example.contactslistview.R;public class ImportingDialog extends Dialog implements ReadDataListener {private static final String LOG_TAG=ImportingDialog.class.getSimpleName();private static final String TAG = "ImportingDialog" ;private TextView tv_person,tv_fail,tv_importing;private ImageView iv_fail;private int mPercent = 0;CustomProgressBar mCustomProgressBar = null;//是否显示private boolean isShow=false;/*** 构造函数*/public ImportingDialog(Context c) {super(c, R.style.dialog);}@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);requestWindowFeature(Window.FEATURE_NO_TITLE);setContentView(R.layout.importing_layout);//导入人数字体tv_person = (TextView)findViewById(R.id.tv_person);//导入进度条mCustomProgressBar =(CustomProgressBar)findViewById(R.id.progress);//导入状态字体-导入中。。。tv_importing = (TextView)findViewById(R.id.tv_importing);//导入失败的图片iv_fail= (ImageView) findViewById(R.id.import_fail);//导入失败的字体tv_fail= (TextView) findViewById(R.id.tv_fail);//百分比设置为0mCustomProgressBar.setProgress(0);Window window = this.getWindow();WindowManager.LayoutParams params = this.getWindow().getAttributes();window.setAttributes(params);}/*** 更新下载进度* */public void notifyByteProgress(int totalByte, int readByte) {Log.d(TAG, "notifyByteProgress totalByte=" + totalByte + " , readByte=" + readByte);final int percent=(int)((double)readByte/totalByte*100);if(percent == mPercent) {return ;}tv_person.setText(readByte+"/"+totalByte);mCustomProgressBar.setProgress(percent);isShow=true;}/*** 导入完毕*/public void onComplete() {// TODO Auto-generated method stubtv_person.setVisibility(View.VISIBLE);mCustomProgressBar.setVisibility(View.VISIBLE);tv_importing.setVisibility(View.VISIBLE);tv_fail.setVisibility(View.GONE);iv_fail.setVisibility(View.GONE);isShow=false;}
/*** 导入失败*/public void onFailed(){tv_person.setVisibility(View.GONE);mCustomProgressBar.setVisibility(View.GONE);tv_importing.setVisibility(View.GONE);tv_fail.setVisibility(View.VISIBLE);iv_fail.setVisibility(View.VISIBLE);isShow=false;}//显示之前初始化界面public void initViewBeforeShow(int sum){LogUtils.i(LOG_TAG, "sum-->>"+sum);tv_person.setVisibility(View.VISIBLE);tv_person.setText(0+"/"+sum);LogUtils.i(LOG_TAG, "sum-->>"+(0+"/"+sum));mCustomProgressBar.setVisibility(View.VISIBLE);isShow=true;}@Overridepublic void onBackPressed() {if (!isShow){super.onBackPressed();}}}
package com.example.contactslistview.bean;/***/
public interface ReadDataListener {/*** this method can't execute pass-time operation.* * @param totalByte* @param readByte*/public void notifyByteProgress(int totalByte, int readByte);public void onComplete();
}
CustomProgressBar
package com.example.contactslistview.bean;import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.view.View;import com.example.contactslistview.R;public class CustomProgressBar extends View {int width;int height;Bitmap sourBg;Bitmap barBg;int currProgress = 0;Handler closeViewHandler = new Handler() {public void handleMessage(Message msg) {if (CustomProgressBar.this.currProgress == 100) {CustomProgressBar.this.setVisibility(View.GONE);CustomProgressBar.this.currProgress = 0;}super.handleMessage(msg);}};/*** 构造函数*/public CustomProgressBar(Context ctx) {super(ctx);}public CustomProgressBar(Context context, AttributeSet attrs,int defStyleAttr) {super(context, attrs, defStyleAttr);}public CustomProgressBar(Context context, AttributeSet attrs) {super(context, attrs);}protected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);this.width = getWidth();this.height = getHeight();// 获取进度条矩形图片 this.sourBg = BitmapFactory.decodeResource(getResources(),R.drawable.pro_state);// 裁剪跟背景图同样大小的矩形图片(非圆角)this.sourBg = conBitmapSize(this.sourBg, this.width, this.height);// if (this.currProgress > 0) {
// setProgress(this.currProgress);
// }}protected void onDraw(Canvas canvas) {if ((this.barBg != null)) {canvas.drawBitmap(this.barBg, 0.0F, 0.0F, null);}super.onDraw(canvas);}/*** 得到控件的宽度,高度* 默认初始化为0进度* importingDialog.notifyByteProgress(localContacts.size(), values[0]);进行发布进度*//** * (1)0 -------- VISIBLE 可见 * (1)4 -------- INVISIBLE 不可见但是占用布局空间 * (1)8 -------- GONE 不可见也不占用布局空间 */public void setProgress(int progress) {try {this.currProgress = progress;// int vis = getVisibility();
//
// if (vis == 8) {
// setVisibility(View.VISIBLE);
// }// if(ferWidth==0){
// ferWidth = 10;
// }int ferWidth = (int) Math.ceil (progress / 100.0F * this.width);if (this.sourBg != null) {this.barBg = cutBitmap(this.sourBg, ferWidth, this.height);this.barBg = toRoundCorner(this.barBg, dip2px(getContext(),4.33f));//4.33f表示进度条的圆角大小invalidate();} else {setVisibility(View.GONE);}if (progress >= 100)this.closeViewHandler.sendMessageDelayed(this.closeViewHandler.obtainMessage(1000), 0L);} catch (Exception e) {e.printStackTrace();}}private Bitmap cutBitmap(Bitmap bitmap, int width, int height) {Bitmap cutBitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height);return cutBitmap;}private Bitmap toRoundCorner(Bitmap bitmap, int pixels) {Bitmap output = Bitmap.createBitmap(bitmap.getWidth(),bitmap.getHeight(), Bitmap.Config.ARGB_8888);Canvas canvas = new Canvas(output);int color = 0xff424242;Paint paint = new Paint();Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());RectF rectF = new RectF(rect);float roundPx = pixels;paint.setAntiAlias(true);canvas.drawARGB(0, 0, 0, 0);paint.setColor(color);canvas.drawRoundRect(rectF, roundPx, roundPx, paint);paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));canvas.drawBitmap(bitmap, rect, rect, paint);return output;}/*** 构造与*/private Bitmap conBitmapSize(Bitmap bitmap, int width, int height) {Matrix matrix = new Matrix();matrix.setScale(1.0F * width / bitmap.getWidth(), 1.0F * height/ bitmap.getHeight());bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(),bitmap.getHeight(), matrix, false);return bitmap;}public static int dip2px(Context context, float dpValue) {final float scale = context.getResources().getDisplayMetrics().density;return (int) (dpValue * scale + 0.5f);}
}
接下里看字幕条类QuickAlphabeticBar
package com.example.contactslistview.bean;import java.util.HashMap;import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Handler;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageButton;
import android.widget.ListView;
import android.widget.TextView;import com.example.contactslistview.R;/*** 字母索引条* * @author Administrator* */
@SuppressLint("ResourceAsColor")
public class QuickAlphabeticBar extends ImageButton {private TextView mDialogText; // 中间显示字母的文本框private Handler mHandler; // 处理UI的句柄private ListView mList; // 列表private float mHight; // 高度// 字母列表索引private String[] letters = new String[] {"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[] array_drawables = new int[]{R.drawable.letter_a,R.drawable.letter_b,R.drawable.letter_c,R.drawable.letter_d,R.drawable.letter_e,R.drawable.letter_f,R.drawable.letter_g,R.drawable.letter_h,R.drawable.letter_i,R.drawable.letter_j,R.drawable.letter_k,R.drawable.letter_l,R.drawable.letter_m,R.drawable.letter_n,R.drawable.letter_o,R.drawable.letter_p,R.drawable.letter_q,R.drawable.letter_r,R.drawable.letter_s,R.drawable.letter_t,R.drawable.letter_u,R.drawable.letter_v,R.drawable.letter_w,R.drawable.letter_x,R.drawable.letter_y,R.drawable.letter_z,R.drawable.letter_end};// 字母索引哈希表private HashMap<String, Integer> alphaIndexer;Paint paint = new Paint();boolean showBkg = false;int choose = -1;/*** 构造函数*/public QuickAlphabeticBar(Context context) {super(context);}public QuickAlphabeticBar(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);}public QuickAlphabeticBar(Context context, AttributeSet attrs) {super(context, attrs);}// 初始化public void init(Activity ctx) {mDialogText = (TextView) ctx.findViewById(R.id.tv_contact_list_fast_position);if (mDialogText != null)mDialogText.setVisibility(View.INVISIBLE);mHandler = new Handler();}// 设置需要索引的列表public void setListView(ListView mList) {this.mList = mList;}/*** String:sortKey Integer:listsContact的角标索引private HashMap<String,Integer> alphaIndexer;*/public void setAlphaIndexer(HashMap<String, Integer> alphaIndexer) {this.alphaIndexer = alphaIndexer;postInvalidate() ;}@Overridepublic boolean onTouchEvent(MotionEvent event) {int act = event.getAction();float y = event.getY();final int oldChoose = choose;//获取控件高度mHight=getHeight();final int selectIndex = (int) (y / (mHight / letters.length));if (selectIndex > -1 && selectIndex < letters.length) {// 防止越界String key = letters[selectIndex];//获取手指触碰点的字母索引if (alphaIndexer.containsKey(key)) {int pos = alphaIndexer.get(key);//获取contactList的对应字母索引的角标if (mList.getHeaderViewsCount() > 0) {this.mList.setSelection(pos+mList.getHeaderViewsCount());} else {this.mList.setSelection(pos);//使listview移动到索引对应的contactList的角标位置}mDialogText.setBackgroundResource(array_drawables[selectIndex]);}}switch (act) {case MotionEvent.ACTION_DOWN:showBkg = true;if (oldChoose != selectIndex) {if (selectIndex >= 0 && selectIndex < letters.length) {if(alphaIndexer.containsKey(letters[selectIndex]))choose = selectIndex;invalidate();}}if(selectIndex > -1 && selectIndex < letters.length &&alphaIndexer.containsKey(letters[selectIndex]))setDialogTextVisiable(VISIBLE);break;case MotionEvent.ACTION_MOVE:if (oldChoose != selectIndex) {if (selectIndex >=0 && selectIndex < letters.length) {if(alphaIndexer.containsKey(letters[selectIndex]))choose = selectIndex;invalidate();}}if(selectIndex > -1 && selectIndex < letters.length && alphaIndexer.containsKey(letters[selectIndex]))setDialogTextVisiable(VISIBLE);break;case MotionEvent.ACTION_UP:showBkg = false;setDialogTextVisiable(INVISIBLE);break;default:break;}return super.onTouchEvent(event);}private void setDialogTextVisiable(final int visiable) {if (mHandler != null) {mHandler.post(new Runnable() {@Overridepublic void run() {if (mDialogText != null) {mDialogText.setVisibility(visiable);}}});}}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);int height = getHeight();int width = getWidth();int sigleHeight = height / letters.length; // 单个字母占的高度for (int i = 0; i < letters.length; i++) {paint.setColor(Color.parseColor("#FFFFFF")); //正常字母颜色paint.setTextSize(getResources().getDimension(R.dimen.textSize_s5));paint.setAntiAlias(true);if(alphaIndexer ==null){return;}if(!alphaIndexer.containsKey(letters[i])){paint.setColor(Color.parseColor("#bbbbbb")); // 没有对应联系人的首字母灰显的颜色paint.setFakeBoldText(true);}// 绘画的位置float xPos = width / 2 - paint.measureText(letters[i]) / 2;float yPos = sigleHeight * i + sigleHeight;canvas.drawText(letters[i], xPos, yPos, paint);paint.reset();}}
}
最后看圆角工具类RoundImageView
package com.example.contactslistview.bean;import com.example.contactslistview.R;import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.Shader.TileMode;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.widget.ImageView;public class RoundImageView extends ImageView{private static final String TAG = RoundImageView.class.getSimpleName();/*** 外部边框的宽和颜色*/private static final int DEFAULT_OUTER_BORDER_WIDTH = 0;private static final int DEFAULT_OUTER_BORDER_COLOR = Color.TRANSPARENT;private int outerWidth = DEFAULT_OUTER_BORDER_WIDTH;private int outerColor = DEFAULT_OUTER_BORDER_COLOR;private static final int COLORDRAWABLE_DIMENSION = 1;/*** 显示图片的类型*/private static final int TYPE_CIRCLE = 0;private static final int TYPE_ROUND = 1;private int showType = TYPE_CIRCLE;/*** 圆角大小的默认值*/private static final int DEFAULT_CORNER_ANGLE = 10;/*** 圆角实际大小值*/private int mCornerAngle = 0;/*** 圆形图片时候半径大小*/private int mCircleRadius = 0;/*** 绘图画笔paint*/private Paint mBitmapPaint = null;private Paint mOuterPaint = null;/*** 3X3缩小放大矩阵*/private Matrix mMatrix = null;/*** 渲染图像,为绘制图形着色*/private BitmapShader mBitmapShader = null;/*** 大小*/private int mCircleViewWidth = 0;private RectF mDrawableRectF = null;private RectF mOuterRectF = null;public RoundImageView(Context context) {this(context, null);}public RoundImageView(Context context, AttributeSet attrs) {this(context, attrs, 0);}public RoundImageView(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);init(attrs);}/*** 初始化操作*/private void init(AttributeSet attrs){TypedArray ta = getContext().obtainStyledAttributes(attrs,R.styleable.RoundImageView);showType = ta.getInt(R.styleable.RoundImageView_show_type, TYPE_CIRCLE);mCornerAngle = ta.getDimensionPixelSize(R.styleable.RoundImageView_corner_angle, dp2px());outerWidth = ta.getDimensionPixelSize(R.styleable.RoundImageView_outer_border_width, DEFAULT_OUTER_BORDER_WIDTH);outerColor = ta.getColor(R.styleable.RoundImageView_outer_border_color, DEFAULT_OUTER_BORDER_COLOR);ta.recycle();mMatrix = new Matrix();mBitmapPaint = new Paint();mBitmapPaint.setAntiAlias(true);mOuterPaint = new Paint();mOuterPaint.setStyle(Paint.Style.STROKE);mOuterPaint.setAntiAlias(true);mOuterPaint.setColor(outerColor);mOuterPaint.setStrokeWidth(outerWidth);}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);/*** 测量的时候,如果获取的类型是圆形的,则强制把view的宽高设为相同大小,以小的为标准*/if(showType == TYPE_CIRCLE){mCircleViewWidth = Math.min(getMeasuredWidth(), getMeasuredHeight());mCircleRadius = mCircleViewWidth / 2 - outerWidth / 2;setMeasuredDimension(mCircleViewWidth, mCircleViewWidth);}}@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);/*** 圆角图片的范围*/if(showType == TYPE_ROUND){mOuterRectF = new RectF(0,0,getWidth(),getHeight());mDrawableRectF = new RectF(outerWidth,outerWidth,getWidth()-outerWidth,getHeight()-outerWidth);}}@Overrideprotected void onDraw(Canvas canvas) {Drawable drawable = getDrawable();if(drawable == null){drawable = getBackground();}if(drawable == null){Log.e(TAG, "[null] drawable is null.");return;}setShader(getBitmapFromDrawable(drawable));switch (showType) {case TYPE_CIRCLE:canvas.drawCircle(getWidth()/2, getHeight()/2, mCircleRadius, mBitmapPaint);canvas.drawCircle(getWidth()/2, getHeight()/2, mCircleRadius, mOuterPaint);break;case TYPE_ROUND:canvas.drawRoundRect(mDrawableRectF, mCornerAngle, mCornerAngle, mBitmapPaint);canvas.drawRoundRect(mOuterRectF, mCornerAngle, mCornerAngle, mOuterPaint);break;}}@Overridepublic void setImageBitmap(Bitmap bm) {if(bm == null){bm = BitmapFactory.decodeResource(getContext().getResources(),R.drawable.contact_photo);}super.setImageBitmap(bm);}/*** 初始化BitmapShader*/private void setShader(Bitmap mBitmap){if(mBitmap == null){Log.i(TAG, "[null] mBitmap is null.");return;}if(mBitmapShader != null){mBitmapShader = null;}/*** 将mBitmap作为着色器,也就是在指定的区域内绘制mBitmap*/mBitmapShader = new BitmapShader(mBitmap, TileMode.CLAMP, TileMode.CLAMP);/*** 缩放比例*/float scale = 1.0f;switch (showType) {case TYPE_CIRCLE:/*** 拿图片的宽高最小值做缩放比例*/scale = mCircleViewWidth * 1.0F / Math.min(mBitmap.getWidth(), mBitmap.getHeight());break;case TYPE_ROUND:/*** 如果图片的宽高与view的宽高不匹配,缩放的宽高一定要大于view的宽高才能填充完整view,所以要取较大值*/scale = Math.max(getWidth() * 1.0f /mBitmap.getWidth() , getHeight() * 1.0f / mBitmap.getHeight() );break;}/*** 变换矩阵设置缩放大小*/mMatrix.setScale(scale,scale);/*** 设置变换矩阵*/mBitmapShader.setLocalMatrix(mMatrix);/*** 设置着色器*/mBitmapPaint.setShader(mBitmapShader);}/*** 从drawable中获取bitmap*/private Bitmap getBitmapFromDrawable(Drawable drawable){if(drawable == null){return null;}if(drawable instanceof BitmapDrawable){return ((BitmapDrawable)drawable).getBitmap();}try {Bitmap bitmap = null;if(drawable instanceof ColorDrawable){bitmap = Bitmap.createBitmap(COLORDRAWABLE_DIMENSION, COLORDRAWABLE_DIMENSION, Bitmap.Config.ARGB_8888);}else{bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(),Bitmap.Config.ARGB_8888);}Canvas canvas = new Canvas(bitmap);drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());drawable.draw(canvas);return bitmap;} catch (OutOfMemoryError e) {e.printStackTrace();return null;}}/*** 根据手机获取合适的像素大小*/private int dp2px(){return (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, DEFAULT_CORNER_ANGLE,getResources().getDisplayMetrics());}
}
最后看drawable里面的东西
delete_btn_anim.xml 取消确定的底部窗口
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"><translateandroid:fromYDelta="100%p"android:toYDelta="0%p"android:duration="600"/>
</set>
selector_cancel.xml 底部窗口的取消
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"><item android:state_pressed="true" android:drawable="@drawable/cancel_p"/><item android:state_pressed="false" android:drawable="@drawable/cancel_n"/><item android:drawable="@drawable/cancel_n"/>
</selector>
selector_sure.xml底部窗口的确定
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"><item android:state_pressed="true" android:drawable="@drawable/sure_p"/><item android:state_pressed="false" android:drawable="@drawable/sure_n"/><item android:drawable="@drawable/sure_n"/>
</selector>
search_bg.xml 搜索背景框
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" ><solid android:color="#FFFFFF" /> <corners android:topLeftRadius="10dp" android:topRightRadius="10dp" android:bottomRightRadius="10dp" android:bottomLeftRadius="10dp"/> </shape>
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_checked="true" android:drawable="@drawable/check_blue" /><!--选中时效果--><item android:state_checked="false" android:drawable="@drawable/unchecked" /><!--未选中时效果--></selector>
selector_row.xml listview 的item的选中背景
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" ><item android:state_pressed="true" android:drawable="@color/background_bg2"/><item android:state_pressed="false" android:drawable="@color/a"/><item android:drawable="@color/a"/>
</selector>
shape_rect_dialog.xml导入dialog的背景
<?xml version="1.0" encoding="utf-8"?>
<shapexmlns:android="http://schemas.android.com/apk/res/android"android:shape="rectangle"><corners android:radius="5dp"/><solid android:color="#f8f8f8"/>
</shape>
<declare-styleable name="RoundImageView"> <attr name="outer_border_width" format="dimension" /> <!-- 边框宽度 --> <attr name="outer_border_color" format="color" /> <!-- 边框颜色 --> <attr name="corner_angle" format="dimension" /> <!-- 圆角大小 --> <attr name="show_type"> <!-- 图片类型 --> <enum name="circle" value="0" /> <!-- 圆形图片 --> <enum name="round" value="1" /> <!-- 圆角图片--> </attr> </declare-styleable> <style name="dialog" parent="@android:style/Theme.Dialog"><item name="android:windowBackground">@android:color/transparent</item></style>
<dimen name="textSize_s5">10sp</dimen>
<?xml version="1.0" encoding="utf-8"?>
<resources><color name="background_bg2">#e6e6e6</color><color name="a">#ffffff</color>
</resources>
这篇关于一款很实用的小demo 字母条索引+自定义进度条+listview/checkbox+长按多选+读取联系人\头像的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!