下载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画出来的
需要把字母列的视图嵌入进Activity中,activity_main.xml如下
然后是汉字转拼音的类
最后就是MainActivity.java
好了,这样就可以实现需要的功能,由于细节比较多,在代码中也都加了注释,需要的话可以下载源码
源码下载地址
对于Listview实现A-Z排序,大家也可以参考
http://blog.csdn.net/jiahui524/article/details/7785606
http://blog.csdn.net/xiaanming/article/details/12684155
这2篇博文的实现
本人在实现此功能时,有些思路和资源也参考了他们的文章.
以下是在本人手机中调试的效果图
要实现此功能
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篇博文的实现
本人在实现此功能时,有些思路和资源也参考了他们的文章.
相关文章推荐
- Android 实现ListView的A-Z字母排序及过滤搜索功能(通讯录)
- 【CSDN下载】第四期:Android实现手机通讯录效果源码、iOS11.2 DeviceSupport
- Android开发实现可拖动排序的ListView功能【附源码下载】
- Android 实现ListView的A-Z字母排序和过滤搜索功能,实现汉字转成拼音
- Android UI开发: 横向ListView(HorizontalListView)及一个简单相册的完整实现 (附源码下载)
- Android实现ListView的A-Z字母排序和过滤搜索功能,实现汉字转成拼音
- Android 使用ListView的A-Z字母排序功能实现联系人模块
- Android 仿美团网,探索ListView的A-Z字母排序功能实现选择城市
- Android UI开发: 横向ListView(HorizontalListView)及一个简单相册的完整实现 (附源码下载)
- Android 实现ListView的A-Z字母排序和过滤搜索功能,实现汉字转成拼音
- Android实现ListView的A-Z字母排序和过滤搜索功能,实现汉字转成拼音
- Android UI开发: 横向ListView(HorizontalListView)完整实现 (附源码下载)
- Android: 横向ListView(HorizontalListView)及一个简单相册的完整实现 (附源码下载)
- Android UI开发: 横向ListView(HorizontalListView)及一个简单相册的完整实现 (附源码下载)
- Android 实现ListView的A-Z字母排序和过滤搜索功能,实现汉字转成拼音
- Android 实现ListView的A-Z字母排序和过滤搜索功能,实现汉字转成拼音
- Android 实现ListView的A-Z字母排序和过滤搜索功能,实现汉字转成拼音 .
- Android 仿联系人列表 实现ListView的A-Z字母排序和过滤搜索功能,并挤压效果
- 快速集成android实现listview的字母A-Z排序,界面侧边字母索引
- Android实现ListView的A-Z字母排序和过滤搜索功能,实现汉字转成拼音