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

下载Android手机通讯录和Listview实现A-Z排序(附源码)

2013-10-18 16:30 489 查看
本章实现的功能:从Android手机中得到通讯录联系人的数据,并且实现A-Z排序和搜索过滤

以下是在本人手机中调试的效果图













要实现此功能

1,通过ContentProvider知识点读取Android手机中联系人数据

对ContentProvider还不熟悉的朋友可以参考下ContentProvider数据共享

记得要在AndroidManifest.xml声明权限<uses-permission android:name="android.permission.READ_CONTACTS" />

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<mAlphabet.length; i++) {
mPaint.setColor(Color.parseColor("#000000"));
mPaint.setAntiAlias(true);
mPaint.setTextSize(23);

float x = width/2 - mPaint.measureText(mAlphabet[i])/2;
float y = singleLetterH*i+singleLetterH;

if(i == mCurPosIdx)
{
mPaint.setColor(Color.parseColor("#0000FF"));
mPaint.setFakeBoldText(true);
}
canvas.drawText(mAlphabet[i], x, y, mPaint);
mPaint.reset();
}

}

@Override
public boolean onTouchEvent(MotionEvent arg0) {

int action = arg0.getAction();
switch(action) {
case MotionEvent.ACTION_DOWN:
mPressed = true;
mCurPosIdx =(int)( arg0.getY()/this.getHeight() * mAlphabet.length);
if(mTouchListener != null && mOldPosIdx!=mCurPosIdx){
if((mCurPosIdx>=0) && (mCurPosIdx<mAlphabet.length)) {
mTouchListener.onTouch(mAlphabet[mCurPosIdx]);
this.invalidate();
}
mOldPosIdx = mCurPosIdx;
}

LetterNotice.setText(mAlphabet[mCurPosIdx]);
LetterNotice.setVisibility(View.VISIBLE);

return true;
case MotionEvent.ACTION_UP:

if (LetterNotice != null) {
LetterNotice.setVisibility(View.INVISIBLE);
}

mPressed = false;
mCurPosIdx = -1;
this.invalidate();
return true;
case MotionEvent.ACTION_MOVE:
mCurPosIdx =(int)( arg0.getY()/this.getHeight() * mAlphabet.length);
if(mTouchListener != null && mCurPosIdx!=mOldPosIdx){
if((mCurPosIdx>=0) && (mCurPosIdx<mAlphabet.length)) {
mTouchListener.onTouch(mAlphabet[mCurPosIdx]);
this.invalidate();
}
mOldPosIdx = mCurPosIdx;
}

if(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;
}
}


需要把字母列的视图嵌入进Activity中,activity_main.xml如下

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >

<EditText
android:id="@+id/pb_search_edit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawableLeft="@drawable/pb_search_contacts"
android:background="@drawable/search_bar_edit_pressed"
android:hint="搜索联系人"
android:textSize="15dip"
android:textColor="#000000"
/>

<FrameLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent" >

<ListView
android:id="@+id/pb_listvew"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:dividerHeight="2dp"
android:divider="#336598"/>

<TextView
android:id="@+id/pb_letter_notice"
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/toast_letter_bg"
android:gravity="center"
android:textColor="#FFFFFF"
android:textSize="50sp"
android:visibility="gone"/>

<TextView
android:id="@+id/pb_nocontacts_notice"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:textColor="#000000"
android:textSize="28dip"
android:text="暂无匹配联系人"
android:visibility="gone"/>

<huahua.mycontacts.AlphabetScrollBar
android:id="@+id/alphabetscrollbar"
android:layout_gravity="right"
android:layout_width="30dp"
android:layout_height="match_parent"/>

</FrameLayout>
</LinearLayout>


然后是汉字转拼音的类

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();
}

}


最后就是MainActivity.java

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> persons = new ArrayList<Persons>();
//搜索过滤联系人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<Persons>{

@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> Persons;
private Context context;

public ListAdapter(Context context,
ArrayList<Persons> persons) {
this.m_inflater = LayoutInflater.from(context);
this.Persons = persons;
this.context = context;
}

//当联系人列表数据发生变化时,用此方法来更新列表
public void updateListView(ArrayList<Persons> 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<Persons> filterpersons = new ArrayList<Persons>();

//遍历所有联系人数组,筛选出包含关键字的联系人
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篇博文的实现

本人在实现此功能时,有些思路和资源也参考了他们的文章.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  界面布局
相关文章推荐