下載Android手機通訊錄和Listview實現A-Z排序(附原始碼)
阿新 • • 發佈:2019-01-30
本章實現的功能:從Android手機中得到通訊錄聯絡人的資料,並且實現A-Z排序和搜尋過濾
以下是在本人手機中除錯的效果圖
要實現此功能
1,通過ContentProvider知識點讀取Android手機中聯絡人資料
記得要在AndroidManifest.xml宣告許可權<uses-permission android:name="android.permission.READ_CONTACTS" />
2,為了方便用到了漢字轉拼音的pinyin4j-2.5.0.jar包,程式碼中需要根據拼音進行排序(不用這個包,用其他方法也可實現漢字轉拼音)
首先來看看最右邊字母列的實現,是直接繼承View畫出來的
需要把字母列的檢視嵌入進Activity中,activity_main.xml如下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; } }
<?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排序,大家也可以參考
這2篇博文的實現
本人在實現此功能時,有些思路和資源也參考了他們的文章.