模仿微信好友列表功能(数据从手机中读取)

quickisbest 2012-12-06

http://www.uml.org.cn/mobiledev/201110121.asp

http://blog.csdn.net/jiahui524/article/details/7785606

感谢这两位的博客:

模仿微信好友列表功能(数据从手机中读取),实现汉首字母排序筛选:

用到了一个pinyin4j-2.5.0.jar这个包

这个包的介绍:http://sourceforge.net/projects/pinyin4j/files/

其中还有一个 ContentResolver的知识点:

http://www.cnblogs.com/ruiyi1987/archive/2011/06/20/2084925.html

这篇文章中用到这样一个查询条件:

  String[] proj1=new String[]{ContactsContract.Contacts.DISPLAY_NAME,

ContactsContract.Contacts.HAS_PHONE_NUMBER,

                                    ContactsContract.Contacts.LOOKUP_KEY};

ContactsContract.Contacts已经不推荐使用,现在推荐使用phone

下面是代码:

main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >
    <FrameLayout
        android:id="@+id/llParent"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:orientation="vertical" >
        <ListView
            android:id="@+id/lvShow"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent" />
        <TextView
            android:id="@+id/tvLetter"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:background="@drawable/show_head_toast_bg"
            android:gravity="center"
            android:maxWidth="70dip"
            android:minWidth="70dip"
            android:padding="10dip"
            android:textColor="#99FFFFFF"
            android:textSize="50sp" >
        </TextView>
        <mypack.aaron.conact.MySideBar
            android:id="@+id/myView"
            android:layout_width="30dip"
            android:layout_height="fill_parent"
            android:layout_gravity="right" >
        </mypack.aaron.conact.MySideBar>
    </FrameLayout>
</LinearLayout>

   list_item.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:descendantFocusability="blocksDescendants"
    android:orientation="vertical">
    <TextView
        android:id="@+id/tv_catalog"
        style="@style/MMListCatalog"
        android:layout_height="wrap_content"
        android:paddingRight="4.0dip" />
    <LinearLayout
        android:id="@+id/contactitem_layout"
        style="@style/MMListItem"
        android:layout_height="56.0dip"
        android:background="@drawable/mm_listitem"
        android:paddingLeft="8.0dip" >
        <ImageView
            android:id="@+id/contactitem_avatar_iv"
            android:layout_width="40.0dip"
            android:layout_height="40.0dip" android:src="@drawable/default_avatar" />
        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1.0"
            android:orientation="vertical"
            android:paddingLeft="8.0dip" >
            <TextView
                android:id="@+id/tv_nick"
                style="@style/MMFontTitleInList"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:singleLine="true" android:text="姓名" />
            <TextView
                android:id="@+id/tv_mobile"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:singleLine="true"
                android:text="13123456789"
                android:textColor="#666666" />
        </LinearLayout>
        <ImageButton
            android:id="@+id/imgbtn_nav"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:layout_marginRight="5dip"
            android:background="@drawable/nav_left"
            android:focusable="false"
            android:focusableInTouchMode="false" />
    </LinearLayout>
</LinearLayout>

    style.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
     <!-- 联系分组样式 -->
    <style name="MMListItem">
        <item name="android:gravity">center_vertical</item>
        <item name="android:orientation">horizontal</item>
        <item name="android:paddingLeft">4.0dip</item>
        <item name="android:paddingTop">4.0dip</item>
        <item name="android:paddingRight">4.0dip</item>
        <item name="android:paddingBottom">4.0dip</item>
        <item name="android:layout_width">fill_parent</item>
        <item name="android:layout_height">wrap_content</item>
    </style>

    <style name="MMFriendListItem">
        <item name="android:gravity">center_vertical</item>
        <item name="android:orientation">horizontal</item>
        <item name="android:paddingLeft">16.0dip</item>
        <item name="android:paddingTop">6.0dip</item>
        <item name="android:paddingRight">6.0dip</item>
        <item name="android:paddingBottom">6.0dip</item>
        <item name="android:layout_width">fill_parent</item>
        <item name="android:layout_height">wrap_content</item>
    </style>

    <style name="MMListCatalog">
        <item name="android:textSize">14.0dip</item>
        <item name="android:textStyle">bold</item>
        <item name="android:textColor">#ff595c61</item>
        <item name="android:gravity">center_vertical</item>
        <item name="android:orientation">horizontal</item>
        <item name="android:background">#ffced2d7</item>
        <item name="android:paddingLeft">10.0dip</item>
        <item name="android:paddingTop">2.0dip</item>
        <item name="android:paddingBottom">2.0dip</item>
        <item name="android:layout_width">fill_parent</item>
        <item name="android:layout_height">wrap_content</item>
    </style>
    <style name="MMFontTitleInList">
        <item name="android:textSize">16.0dip</item>
        <item name="android:textColor">#ff595c61</item>
        <item name="android:ellipsize">end</item>
        <item name="android:gravity">center_vertical</item>
        <item name="android:layout_width">wrap_content</item>
        <item name="android:layout_height">wrap_content</item>
        <item name="android:singleLine">true</item>
    </style>

    <style name="MMFontTipInList">
        <item name="android:textSize">14.0dip</item>
        <item name="android:textColor">#fff</item>
        <item name="android:ellipsize">end</item>
        <item name="android:gravity">center_vertical</item>
        <item name="android:layout_width">wrap_content</item>
        <item name="android:layout_height">wrap_content</item>
        <item name="android:singleLine">true</item>
    </style>
</resources>

 PinyinUtils.java 

这个java文件是生成汉字首字母拼音

  public class PinyinUtils {

// 获得汉语拼音首字母
		public static String getAlpha(String chines) {
			String pinyinName = "";
			char[] nameChar = chines.toCharArray();
			HanyuPinyinOutputFormat defaultFormat = new HanyuPinyinOutputFormat();
			defaultFormat.setCaseType(HanyuPinyinCaseType.UPPERCASE);
			defaultFormat.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
			for (int i = 0; i < nameChar.length; i++) {
				if (nameChar[i] > 128) {
					try {
						pinyinName += PinyinHelper.toHanyuPinyinStringArray(
								nameChar[i], defaultFormat)[0].charAt(0);
					} catch (BadHanyuPinyinOutputFormatCombination e) {
						e.printStackTrace();
					}
				} else {
					pinyinName += nameChar[i];
				}
			}
			return pinyinName;
		}

		/**
		 * 将字符串中的中文转化为拼音,其他字符不变
		 * 
		 * @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 (int i = 0; i < input.length; i++) {
					if (java.lang.Character.toString(input[i]).matches(
							"[\\u4E00-\\u9FA5]+")) {
						String[] temp = PinyinHelper.toHanyuPinyinStringArray(
								input[i], format);
						output += temp[0];
					} else
						output += java.lang.Character.toString(input[i]);
				}
			} catch (BadHanyuPinyinOutputFormatCombination e) {
				e.printStackTrace();
			}
			return output;
		}

		/**
		 * 汉字转换位汉语拼音首字母,英文字符不变
		 * 
		 * @param chines
		 *            汉字
		 * @return 拼音
		 */
		public static String converterToFirstSpell(String chines) {
			String pinyinName = "";
			char[] nameChar = chines.toCharArray();
			HanyuPinyinOutputFormat defaultFormat = new HanyuPinyinOutputFormat();
			defaultFormat.setCaseType(HanyuPinyinCaseType.UPPERCASE);
			defaultFormat.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
			for (int i = 0; i < nameChar.length; i++) {
				if (nameChar[i] > 128) {
					try {
						pinyinName += PinyinHelper.toHanyuPinyinStringArray(
								nameChar[i], defaultFormat)[0].charAt(0);
					} catch (BadHanyuPinyinOutputFormatCombination e) {
						e.printStackTrace();
					}
				} else {
					pinyinName += nameChar[i];
				}
			}
			return pinyinName;
		}
}

   MySideBar.java

  右边拼音

public class MySideBar  extends View{
	OnTouchingLetterChangedListener onTouchingLetterChangedListener;
	// 26个字母
	public static String[] b = { "#", "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" };
	int choose = -1;
	Paint paint = new Paint();

	public MySideBar(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
	}

	public MySideBar(Context context, AttributeSet attrs) {
		super(context, attrs);
	}

	public MySideBar(Context context) {
		super(context);
	}

	/**
	 * 重写这个方法
	 */
	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);
		if (showBkg) {
			canvas.drawColor(Color.parseColor("#40000000"));
		}

		int height = getHeight();
		int width = getWidth();
		int singleHeight = height / b.length;
		for (int i = 0; i < b.length; i++) {
			paint.setColor(Color.BLACK);
			// paint.setColor(Color.WHITE);
			paint.setTypeface(Typeface.DEFAULT_BOLD);
			paint.setAntiAlias(true);
			paint.setTextSize(20);
			if (i == choose) {
				paint.setColor(Color.parseColor("#3399ff"));
				paint.setFakeBoldText(true);
			}
			float xPos = width / 2 - paint.measureText(b[i]) / 2;
			float yPos = singleHeight * i + singleHeight;
			canvas.drawText(b[i], xPos, yPos, paint);
			paint.reset();
		}

	}

	private boolean showBkg = false;

	@Override
	public boolean dispatchTouchEvent(MotionEvent event) {
		final int action = event.getAction();
		final float y = event.getY();
		final int oldChoose = choose;
		final OnTouchingLetterChangedListener listener = onTouchingLetterChangedListener;
		final int c = (int) (y / getHeight() * b.length);

		switch (action) {
		case MotionEvent.ACTION_DOWN:
			showBkg = true;
			if (oldChoose != c && listener != null) {
				if (c > 0 && c < b.length) {
					listener.onTouchingLetterChanged(b[c]);
					choose = c;
					invalidate();
				}
			}

			break;
		case MotionEvent.ACTION_MOVE:
			if (oldChoose != c && listener != null) {
				if (c > 0 && c < b.length) {
					listener.onTouchingLetterChanged(b[c]);
					choose = c;
					invalidate();
				}
			}
			break;
		case MotionEvent.ACTION_UP:
			showBkg = false;
			choose = -1;
			invalidate();
			break;
		}
		return true;
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		return super.onTouchEvent(event);
	}

	/**
	 * 向外公开的方法
	 * 
	 * @param onTouchingLetterChangedListener
	 */
	public void setOnTouchingLetterChangedListener(
			OnTouchingLetterChangedListener onTouchingLetterChangedListener) {
		this.onTouchingLetterChangedListener = onTouchingLetterChangedListener;
	}

	/**
	 * 接口
	 * 
	 * @author coder
	 * 
	 */
	public interface OnTouchingLetterChangedListener {
		public void onTouchingLetterChanged(String s);
	}
}

  public class PinyinComparator implements Comparator{

/** 按首字母排序**/
	@Override
	public int compare(Object o1, Object o2) {
		 String str1 = PinyinUtils.getPingYin((String) o1);
	     String str2 = PinyinUtils.getPingYin((String) o2);
	     return str1.compareTo(str2);
	}
//	
//	@Override
//	public int compare(Object o1, Object o2) {
//		 String str1 = PinyinUtils.getPingYin(((UserInfo) o1).getPy());
//	     String str2 = PinyinUtils.getPingYin(((UserInfo) o2).getPy());
//	     return str1.compareTo(str2);
//	}

}
 

  最后就是activity:

public class ContactsActivity extends Activity implements OnTouchingLetterChangedListener {
 private ListView lv_list;
 /**联系人显示名称**/  
 private static final int PHONES_DISPLAY_NAME_INDEX = 0;  
 /**电话号码**/  
 private static final int PHONES_NUMBER_INDEX = 1;  
 /**头像ID**/  
 private static final int PHONES_PHOTO_ID_INDEX = 2;  
 /**联系人的ID**/  
 private static final int PHONES_CONTACT_ID_INDEX = 3;  
 /**联系人名称**/  
 private ArrayList<String> mContactsName = new ArrayList<String>();  
 /**联系人头像**/  
 private ArrayList<String> mContactsNumber = new ArrayList<String>();  
 /**联系人头像**/  
 private ArrayList<Bitmap> mContactsPhonto = new ArrayList<Bitmap>(); 
 /**拼音**/
 private ArrayList<String> mPy=new ArrayList<String>();
 /**左侧拼音字母**/
 private MySideBar myView;
 /**显示到屏幕中间的拼音**/
 private TextView overlay;
	
 private OverlayThread overlayThread = new OverlayThread();

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        lv_list=(ListView)findViewById(R.id.lv_lsit);
        overlay=(TextView)findViewById(R.id.tvLetter);

        lv_list.setTextFilterEnabled(true);
		overlay.setVisibility(View.INVISIBLE);//默认隐藏
        
        
		myView = (MySideBar) findViewById(R.id.myView);
		myView.setOnTouchingLetterChangedListener(this);

		
	  ContentResolver resolver = getContentResolver();  
        String[] proj1=new String[]{Phone.DISPLAY_NAME,
                Phone.NUMBER,Phone.PHOTO_ID,Phone.CONTACT_ID,
              };
        Cursor curContacts=resolver.query(Phone.CONTENT_URI,proj1, null, null, null);
        if(curContacts.getCount()>0){
            while(curContacts.moveToNext()){  
            	//得到手机号码  
                String phoneNumber = curContacts.getString(PHONES_NUMBER_INDEX); 
               //当手机号码为空的或者为空字段 跳过当前循环  

                if (TextUtils.isEmpty(phoneNumber)){
                    continue; 
                }  
                //得到联系人名称  

                String contactName = curContacts.getString(PHONES_DISPLAY_NAME_INDEX); 
                //拼音
                String py=PinyinUtils.getAlpha(contactName);

                //得到联系人ID  

                Long contactid = curContacts.getLong(PHONES_CONTACT_ID_INDEX);  

                //得到联系人头像ID  

                Long photoid = curContacts.getLong(PHONES_PHOTO_ID_INDEX);  

                //得到联系人头像Bitamp  

                Bitmap contactPhoto = null;  

                //photoid 大于0 表示联系人有头像 如果没有给此人设置头像则给他一个默认的  

                if(photoid > 0 ) {  

                    Uri uri =ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI,contactid);  

                    InputStream input = ContactsContract.Contacts.openContactPhotoInputStream(resolver, uri);  

                    contactPhoto = BitmapFactory.decodeStream(input);  

                }else {  

                    contactPhoto = BitmapFactory.decodeResource(getResources(), R.drawable.contact_photo);  

                }  
                mContactsName.add(contactName);
                mContactsPhonto.add(contactPhoto);
                mContactsNumber.add(phoneNumber);
                mPy.add(py);
                
            	

            } Collections.sort(mContactsName, new PinyinComparator()); //ArrayList按首字母拼音排序
            curContacts.close();
        }
      ListViewAdapter ltAdapter=new ListViewAdapter();
      lv_list.setAdapter(ltAdapter);
    }
    /**绑定数据**/
    public class ListViewAdapter extends BaseAdapter{

 
		@Override
		public int getCount() {
			// TODO Auto-generated method stub
			return mContactsName.size();
		}

		@Override
		public Object getItem(int position) {
			// TODO Auto-generated method stub
			return position;
		}

		@Override
		public long getItemId(int position) {
			// TODO Auto-generated method stub
			return position;
		}

		@Override
		public View getView(int position, View convertView, ViewGroup parent) {
			LayoutInflater inflater =getLayoutInflater();
			  
            // 使用View的对象itemView与R.layout.item关联  
			if(convertView==null){
				convertView=inflater.inflate(R.layout.list_item, null);  
			}
 
            // 通过findViewById()方法实例R.layout.item内各组件  
            TextView tvName = (TextView) convertView.findViewById(R.id.tv_nick);  
            TextView tvPhone=(TextView) convertView.findViewById(R.id.tv_mobile);
            ImageView iv_pic = (ImageView) convertView.findViewById(R.id.contactitem_avatar_iv);  
            TextView tv_catalog=(TextView)convertView.findViewById(R.id.tv_catalog);
            
            /*首字拼音*/
            String catalog = PinyinUtils.converterToFirstSpell(mContactsName.get(position).substring(0, 1));
            
            if(position==0){
            	tv_catalog.setVisibility(View.VISIBLE);
    			tv_catalog.setText(catalog);
            }else {
            	/*下一个汉字首字拼音,如果两个汉字的首字母相等,下一个汉字的tv_catalog隐藏,这里其实就是把相同首字母的汉字叠加在一起*/
    			String lastCatalog = PinyinUtils.converterToFirstSpell(mContactsName.get(position - 1)).substring(0,1);
    			if (catalog.equals(lastCatalog)) {
    				tv_catalog.setVisibility(View.GONE);
    			} else {
    				tv_catalog.setVisibility(View.VISIBLE);
    				tv_catalog.setText(catalog);
    			}
    		}
            
            tvName.setText(mContactsName.get(position));  
            iv_pic.setImageBitmap(mContactsPhonto.get(position)); 
            tvPhone.setText(mContactsNumber.get(position));
            return convertView;  
		}
    }
	/*下面是触摸左侧拼音*/

    private Handler handler = new Handler() {
	};

	private class OverlayThread implements Runnable {

		public void run() {
			overlay.setVisibility(View.GONE);
		}

	}
    
	/**字母触摸事件**/
	@Override
	public void onTouchingLetterChanged(String s) {
		Log.i("coder", "s:" + s);

		overlay.setText(s);
		overlay.setVisibility(View.VISIBLE);
		handler.removeCallbacks(overlayThread);
		handler.postDelayed(overlayThread, 1000);
		if (alphaIndexer(s) > 0) {
			int position = alphaIndexer(s);
			Log.i("coder", "position:" + position);
			lv_list.setSelection(position);

		}		
	}
	//根据 字母的值找到mPy存储的汉字首字母拼音的索引,listView中根据这个索引定位显示
	public int alphaIndexer(String s) {
		int position = 0;
		for (int i = 0; i < mContactsPhonto.size(); i++) {
			if (mPy.get(i).startsWith(s)) {
				position = i;
				break;
			}
		}
		Log.i("coder", "i" + position + mPy.get(position));
		return position;
	}
    
}

 经过了手机测试成功,代码比较臃肿,还没有实现输入筛选条件查询,正在研究中

相关推荐