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

本章实现的功能:从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篇博文的实现

本人在实现此功能时,有些思路和资源也参考了他们的文章.


发布了21 篇原创文章 · 获赞 8 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/zhangxuebing2/article/details/12854113