本章实现的功能:从Android手机中得到通讯录联系人的数据,并且实现A-Z排序和搜索过滤
以下是在本人手机中调试的效果图
要实现此功能
1,通过ContentProvider知识点读取Android手机中联系人数据
对ContentProvider还不熟悉的朋友可以参考下ContentProvider数据共享
记得要在AndroidManifest.xml声明权限
2,为了方便用到了汉字转拼音的pinyin4j-2.5.0.jar包,代码中需要根据拼音进行排序(不用这个包,用其他方法也可实现汉字转拼音)
首先来看看最右边字母列的实现,是直接继承View画出来的
package huahua.mycontacts;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.TextView;
public class AlphabetScrollBar extends View {
private Paint mPaint = new Paint();
private String[] mAlphabet = 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 boolean mPressed;
private int mCurPosIdx = -1;
private int mOldPosIdx = -1;
private OnTouchBarListener mTouchListener;
private TextView LetterNotice;
public AlphabetScrollBar(Context arg0, AttributeSet arg1, int arg2) {
super(arg0, arg1, arg2);
// TODO Auto-generated constructor stub
}
public AlphabetScrollBar(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
}
public AlphabetScrollBar(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
public void setTextView(TextView LetterNotice) {
this.LetterNotice = LetterNotice;
}
@Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
int width = this.getWidth();
int height = this.getHeight();
int singleLetterH = height/mAlphabet.length;
if(mPressed) {
//如果处于按下状态,改变背景及相应字体的颜色
canvas.drawColor(Color.parseColor("#40000000"));
}
for(int i=0; i=0) && (mCurPosIdx=0) && (mCurPosIdx= 0 && mCurPosIdx < mAlphabet.length)
{
LetterNotice.setText(mAlphabet[mCurPosIdx]);
LetterNotice.setVisibility(View.VISIBLE);
}
return true;
default:
return super.onTouchEvent(arg0);
}
}
/**
* 接口
*/
public static interface OnTouchBarListener {
void onTouch(String letter);
}
/**
* 向外公开的方法
*/
public void setOnTouchBarListener (OnTouchBarListener listener) {
mTouchListener = listener;
}
}
package huahua.mycontacts;
import net.sourceforge.pinyin4j.PinyinHelper;
import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType;
import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat;
import net.sourceforge.pinyin4j.format.HanyuPinyinToneType;
import net.sourceforge.pinyin4j.format.HanyuPinyinVCharType;
import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination;
/**
* 拼音帮助类
*/
public class PinyinUtils {
/**
* 将字符串中的中文转化为拼音,其他字符不变
* 花花大神->huahuadashen
* @param inputString
* @return
*/
public static String getPingYin(String inputString) {
HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat();
format.setCaseType(HanyuPinyinCaseType.LOWERCASE);
format.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
format.setVCharType(HanyuPinyinVCharType.WITH_V);
char[] input = inputString.trim().toCharArray();
String output = "";
try {
for (char curchar : input) {
if (java.lang.Character.toString(curchar).matches(
"[\\u4E00-\\u9FA5]+")) {
String[] temp = PinyinHelper.toHanyuPinyinStringArray(
curchar, format);
output += temp[0];
} else
output += java.lang.Character.toString(curchar);
}
} catch (BadHanyuPinyinOutputFormatCombination e) {
e.printStackTrace();
}
return output;
}
/**
* 汉字转换为汉语拼音首字母,英文字符不变
* 花花大神->hhds
* @param chines
* 汉字
* @return 拼音
*/
public static String getFirstSpell(String chinese) {
StringBuffer pybf = new StringBuffer();
char[] arr = chinese.toCharArray();
HanyuPinyinOutputFormat defaultFormat = new HanyuPinyinOutputFormat();
defaultFormat.setCaseType(HanyuPinyinCaseType.LOWERCASE);
defaultFormat.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
for (char curchar : arr) {
if (curchar > 128) {
try {
String[] temp = PinyinHelper.toHanyuPinyinStringArray(curchar, defaultFormat);
if (temp != null) {
pybf.append(temp[0].charAt(0));
}
} catch (BadHanyuPinyinOutputFormatCombination e) {
e.printStackTrace();
}
} else {
pybf.append(curchar);
}
}
return pybf.toString().replaceAll("\\W", "").trim();
}
}
package huahua.mycontacts;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.provider.ContactsContract.CommonDataKinds;
import android.app.Activity;
import android.content.ContentResolver;
import android.content.Context;
import android.database.Cursor;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.TextView;
public class MainActivity extends Activity {
//联系人包含的信息
public static class Persons {
public String Name; //姓名
public String PY; //姓名拼音 (花花大神:huahuadashen)
public String Number; //电话号码
public String FisrtSpell; //中文名首字母 (花花大神:hhds)
}
//字母列视图View
private AlphabetScrollBar m_asb;
//显示选中的字母
private TextView m_letterNotice;
//联系人的列表
private ListView m_contactslist;
//联系人列表的适配器
private ListAdapter m_listadapter;
//所有联系人数组
private ArrayList persons = new ArrayList();
//搜索过滤联系人EditText
private EditText m_FilterEditText;
//没有匹配联系人时显示的TextView
private TextView m_listEmptyText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//获取手机中的联系人,并将所有联系人保存perosns数组中
//联系人比较多的话,初始化中会比较耗时,以后再优化
getContacts();
//得到字母列的对象,并设置触摸响应监听器
m_asb = (AlphabetScrollBar)findViewById(R.id.alphabetscrollbar);
m_asb.setOnTouchBarListener(new ScrollBarListener());
m_letterNotice = (TextView)findViewById(R.id.pb_letter_notice);
m_asb.setTextView(m_letterNotice);
// 根据拼音为联系人数组进行排序
Collections.sort(persons, new ComparatorPY());
//得到联系人列表,并设置适配器
m_contactslist = (ListView)findViewById(R.id.pb_listvew);
m_listadapter = new ListAdapter(this, persons);
m_contactslist.setAdapter(m_listadapter);
m_listEmptyText = (TextView)findViewById(R.id.pb_nocontacts_notice);
//初始化搜索编辑框,设置文本改变时的监听器
m_FilterEditText = (EditText)findViewById(R.id.pb_search_edit);
m_FilterEditText.addTextChangedListener(new TextWatcher() {
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if(!"".equals(s.toString().trim()))
{
//根据编辑框值过滤联系人并更新联系列表
filterContacts(s.toString().trim());
m_asb.setVisibility(View.GONE);
}
else
{
m_asb.setVisibility(View.VISIBLE);
m_listadapter.updateListView(persons);
}
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
// TODO Auto-generated method stub
}
@Override
public void afterTextChanged(Editable s) {
// TODO Auto-generated method stub
}
});
}
public class ComparatorPY implements Comparator{
@Override
public int compare(Persons lhs, Persons rhs) {
String str1 = lhs.PY;
String str2 = rhs.PY;
return str1.compareToIgnoreCase(str2);
}
}
public class ListAdapter extends BaseAdapter{
private LayoutInflater m_inflater;
private ArrayList Persons;
private Context context;
public ListAdapter(Context context,
ArrayList persons) {
this.m_inflater = LayoutInflater.from(context);
this.Persons = persons;
this.context = context;
}
//当联系人列表数据发生变化时,用此方法来更新列表
public void updateListView(ArrayList persons){
this.Persons = persons;
notifyDataSetChanged();
}
@Override
public int getCount() {
// TODO Auto-generated method stub
return Persons.size();
}
@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return Persons.get(position);
}
@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
convertView = m_inflater.inflate(R.layout.list_item, null);
TextView name = (TextView) convertView.findViewById(R.id.contacts_name);
name.setText(Persons.get(position).Name);
TextView number = (TextView) convertView.findViewById(R.id.contacts_number);
number.setText(Persons.get(position).Number);
//字母提示textview的显示
TextView letterTag = (TextView)convertView.findViewById(R.id.pb_item_LetterTag);
//获得当前姓名的拼音首字母
String firstLetter = Persons.get(position).PY.substring(0,1).toUpperCase();
//如果是第1个联系人 那么letterTag始终要显示
if(position == 0)
{
letterTag.setVisibility(View.VISIBLE);
letterTag.setText(firstLetter);
}
else
{
//获得上一个姓名的拼音首字母
String firstLetterPre = Persons.get(position-1).PY.substring(0,1).toUpperCase();
//比较一下两者是否相同
if(firstLetter.equals(firstLetterPre))
{
letterTag.setVisibility(View.GONE);
}
else
{
letterTag.setVisibility(View.VISIBLE);
letterTag.setText(firstLetter);
}
}
return convertView;
}
}
//字母列触摸的监听器
private class ScrollBarListener implements AlphabetScrollBar.OnTouchBarListener {
@Override
public void onTouch(String letter) {
//触摸字母列时,将联系人列表更新到首字母出现的位置
for (int i = 0; i < persons.size(); i++) {
if (persons.get(i).PY.substring(0, 1).compareToIgnoreCase(letter) == 0) {
m_contactslist.setSelection(i);
break;
}
}
}
}
public void getContacts() {
ContentResolver contentResolver = getContentResolver();
// 获得所有联系人数据集的游标
Cursor cursor = contentResolver.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI ,null, null, null, null);
// 循环遍历
if (cursor.moveToFirst()) {
int idColumn = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone._ID);
int displayNameColumn = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME);
int NumberColumn = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER);
while (cursor.moveToNext()){
Persons person = new Persons();
// 获得联系人的ID号
String contactId = cursor.getString(idColumn);
// 获得联系人姓名
person.Name = cursor.getString(displayNameColumn);
person.PY = PinyinUtils.getPingYin(person.Name);
person.FisrtSpell = PinyinUtils.getFirstSpell(person.Name);
person.Number = cursor.getString(NumberColumn);
Log.v("huahua", "名字:"+person.Name + "号码:"+person.Number + "姓名首字母:"+person.FisrtSpell );
persons.add(person);
}
cursor.close();
}
}
private void filterContacts(String filterStr){
ArrayList filterpersons = new ArrayList();
//遍历所有联系人数组,筛选出包含关键字的联系人
for (int i = 0; i < persons.size(); i++) {
//过滤的条件
if (isStrInString(persons.get(i).Number,filterStr)
||isStrInString(persons.get(i).PY,filterStr)
||persons.get(i).Name.contains(filterStr)
||isStrInString(persons.get(i).FisrtSpell,filterStr)){
//将筛选出来的联系人重新添加到filterpersons数组中
Persons filterperson = new Persons();
filterperson.Name = persons.get(i).Name;
filterperson.PY = persons.get(i).PY;
filterperson.Number = persons.get(i).Number;
filterperson.FisrtSpell = persons.get(i).FisrtSpell;
filterpersons.add(filterperson);
}
}
//如果没有匹配的联系人
if(filterpersons.isEmpty())
{
m_contactslist.setEmptyView(m_listEmptyText);
}
//将列表更新为过滤的联系人
m_listadapter.updateListView(filterpersons);
}
public boolean isStrInString(String bigStr,String smallStr){
if(bigStr.toUpperCase().indexOf(smallStr.toUpperCase())>-1){
return true;
}else{
return false;
}
}
}
好了,这样就可以实现需要的功能,由于细节比较多,在代码中也都加了注释,需要的话可以下载源码
源码下载地址
对于Listview实现A-Z排序,大家也可以参考
http://blog.csdn.net/jiahui524/article/details/7785606
http://blog.csdn.net/xiaanming/article/details/12684155
这2篇博文的实现
本人在实现此功能时,有些思路和资源也参考了他们的文章.