Android 實現系統聯繫人軟件的分組和字母表導航效果(優化版)

以下代碼經過測試,可以通過,無需下載,只要照着執行就可以run

注意:

androidmanifest.xml文件中添加以下權限

<uses-permission android:name="android.permission.READ_CONTACTS" />

注意正則表達式的那塊代碼,很多轉載的文章那裏代碼直接ctrl+c是錯誤的

解惑:

當你電話本中沒有數據的時候,應該沒有數據;當電話本中沒有P打頭的,你現在點擊P導航,也是無法切的P的位置,其他字母類似。

1.FastContactSearchDemoActivity.java

[java] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. package com.zhf.FastContactSearchWithAlphabeticBarDemo;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.Collections;  
  5. import java.util.HashMap;  
  6. import java.util.List;  
  7. import java.util.Set;  
  8. import java.util.regex.Pattern;  
  9. import com.zhf.FastContactSearchDemo.R;  
  10. import android.app.Activity;  
  11. import android.content.AsyncQueryHandler;  
  12. import android.content.ContentResolver;  
  13. import android.content.ContentValues;  
  14. import android.content.Context;  
  15. import android.database.Cursor;  
  16. import android.net.Uri;  
  17. import android.os.Bundle;  
  18. import android.view.LayoutInflater;  
  19. import android.view.View;  
  20. import android.view.ViewGroup;  
  21. import android.widget.BaseAdapter;  
  22. import android.widget.ListView;  
  23. import android.widget.TextView;  
  24.   
  25. /** 
  26.  * 聯繫人分章節顯示、ListView快速滑動顯示聯繫人首字母、附帶字母表快速查找的例子 
  27.  * 查閱網絡資源,實現方式都是比較複雜,尤其有些還實現了SectionIndex接口,很多人不怎麼能理解,研究後發現此種類型的例子沒必要也不應該那麼實現 
  28.  * @author [email protected] 
  29.  *  
  30.  */  
  31. public class FastContactSearchDemoActivity extends Activity {  
  32.     private BaseAdapter adapter;  
  33.     private ListView personList;  
  34.     private List<ContentValues> list;  
  35.     private AsyncQueryHandler asyncQuery;  
  36.     private QuickAlphabeticBar alpha;  
  37.     private static final String NAME = "name", NUMBER = "number",  
  38.             SORT_KEY = "sort_key";  
  39.   
  40.     @Override  
  41.     public void onCreate(Bundle savedInstanceState) {  
  42.         super.onCreate(savedInstanceState);  
  43.         setContentView(R.layout.main);  
  44.         personList = (ListView) findViewById(R.id.listView);  
  45.         alpha = (QuickAlphabeticBar) findViewById(R.id.fast_scroller);  
  46.   
  47.         asyncQuery = new MyAsyncQueryHandler(getContentResolver());  
  48.     }  
  49.   
  50.     @Override  
  51.     protected void onResume() {  
  52.         super.onResume();  
  53.         Uri uri = Uri.parse("content://com.android.contacts/data/phones"); // 聯繫人的Uri  
  54.         String[] projection = { "_id""display_name""data1""sort_key" }; // 查詢的列  
  55.         asyncQuery.startQuery(0null, uri, projection, nullnull,  
  56.                 "sort_key COLLATE LOCALIZED asc"); // 按照sort_key升序查詢  
  57.     }  
  58.   
  59.     /** 
  60.      * 數據庫異步查詢類AsyncQueryHandler 
  61.      *  
  62.      * @author administrator 
  63.      *  
  64.      */  
  65.     private class MyAsyncQueryHandler extends AsyncQueryHandler {  
  66.   
  67.         public MyAsyncQueryHandler(ContentResolver cr) {  
  68.             super(cr);  
  69.   
  70.         }  
  71.   
  72.         /** 
  73.          * 查詢結束的回調函數 
  74.          */  
  75.         @Override  
  76.         protected void onQueryComplete(int token, Object cookie, Cursor cursor) {  
  77.             if (cursor != null && cursor.getCount() > 0) {  
  78.                 list = new ArrayList<ContentValues>();  
  79.                 cursor.moveToFirst();  
  80.                 for (int i = 0; i < cursor.getCount(); i++) {  
  81.                     ContentValues cv = new ContentValues();  
  82.                     cursor.moveToPosition(i);  
  83.                     String name = cursor.getString(1);  
  84.                     String number = cursor.getString(2);  
  85.                     String sortKey = cursor.getString(3);  
  86.   
  87.                     if (number.startsWith("+86")) {// 去除多餘的中國地區號碼標誌,對這個程序沒有影響。  
  88.                         cv.put(NAME, name);  
  89.                         cv.put(NUMBER, number.substring(3));  
  90.                         cv.put(SORT_KEY, sortKey);  
  91.                     } else {  
  92.                         cv.put(NAME, name);  
  93.                         cv.put(NUMBER, number);  
  94.                         cv.put(SORT_KEY, sortKey);  
  95.                     }  
  96.                     list.add(cv);  
  97.                 }  
  98.                 if (list.size() > 0) {  
  99.                     setAdapter(list);  
  100.                 }  
  101.             }  
  102.         }  
  103.   
  104.     }  
  105.   
  106.     private void setAdapter(List<ContentValues> list) {  
  107.         adapter = new ListAdapter(this, list);  
  108.         personList.setAdapter(adapter);  
  109.         alpha.init(FastContactSearchDemoActivity.this);  
  110.         alpha.setListView(personList);  
  111.         alpha.setHight(alpha.getHeight());  
  112.         alpha.setVisibility(View.VISIBLE);  
  113.     }  
  114.   
  115.     private static class ViewHolder {  
  116.         TextView alpha;  
  117.         TextView name;  
  118.         TextView number;  
  119.     }  
  120.   
  121.     /* 
  122.      * 移植時只需要提供一個已排序的集合list即可 
  123.      */  
  124.     private class ListAdapter extends BaseAdapter{  
  125.         private LayoutInflater inflater;  
  126.         private List<ContentValues> list;  
  127.         private HashMap<String, Integer> alphaIndexer;//保存每個索引在list中的位置【#-0,A-4,B-10】  
  128.         private String[] sections;//每個分組的索引表【A,B,C,F...】  
  129.   
  130.         public ListAdapter(Context context, List<ContentValues> list) {  
  131.             this.inflater = LayoutInflater.from(context);  
  132.             this.list = list; // 該list是已經排序過的集合,有些項目中的數據必須要自己進行排序。  
  133.             this.alphaIndexer = new HashMap<String, Integer>();  
  134.             this.sections = new String[list.size()];  
  135.   
  136.             for (int i =0; i <list.size(); i++) {  
  137.                 String name = getAlpha(list.get(i).getAsString(SORT_KEY));  
  138.                 if(!alphaIndexer.containsKey(name)){//只記錄在list中首次出現的位置  
  139.                     alphaIndexer.put(name, i);  
  140.                 }  
  141.             }  
  142.             Set<String> sectionLetters = alphaIndexer.keySet();  
  143.             ArrayList<String> sectionList = new ArrayList<String>(  
  144.                     sectionLetters);  
  145.             Collections.sort(sectionList);  
  146.             sections = new String[sectionList.size()];  
  147.             sectionList.toArray(sections);  
  148.               
  149.             alpha.setAlphaIndexer(alphaIndexer);  
  150.         }  
  151.   
  152.         @Override  
  153.         public int getCount() {  
  154.             return list.size();  
  155.         }  
  156.   
  157.         @Override  
  158.         public Object getItem(int position) {  
  159.             return list.get(position);  
  160.         }  
  161.   
  162.         @Override  
  163.         public long getItemId(int position) {  
  164.             return position;  
  165.         }  
  166.   
  167.         @Override  
  168.         public View getView(int position, View convertView, ViewGroup parent) {  
  169.             ViewHolder holder;  
  170.   
  171.             if (convertView == null) {  
  172.                 convertView = inflater.inflate(R.layout.list_item, null);  
  173.                 holder = new ViewHolder();  
  174.                 holder.alpha = (TextView) convertView.findViewById(R.id.alpha);  
  175.                 holder.name = (TextView) convertView.findViewById(R.id.name);  
  176.                 holder.number = (TextView) convertView  
  177.                         .findViewById(R.id.number);  
  178.                 convertView.setTag(holder);  
  179.             } else {  
  180.                 holder = (ViewHolder) convertView.getTag();  
  181.             }  
  182.             ContentValues cv = list.get(position);  
  183.             String name = cv.getAsString(NAME);  
  184.             String number = cv.getAsString(NUMBER);  
  185.             holder.name.setText(name);  
  186.             holder.number.setText(number);  
  187.   
  188.             // 當前聯繫人的sortKey  
  189.             String currentStr = getAlpha(list.get(position).getAsString(  
  190.                     SORT_KEY));  
  191.             // 上一個聯繫人的sortKey  
  192.             String previewStr = (position - 1) >= 0 ? getAlpha(list.get(  
  193.                     position - 1).getAsString(SORT_KEY)) : " ";  
  194.             /** 
  195.              * 判斷顯示#、A-Z的TextView隱藏與可見 
  196.              */  
  197.             if (!previewStr.equals(currentStr)) { // 當前聯繫人的sortKey!=上一個聯繫人的sortKey,說明當前聯繫人是新組。  
  198.                 holder.alpha.setVisibility(View.VISIBLE);  
  199.                 holder.alpha.setText(currentStr);  
  200.             } else {  
  201.                 holder.alpha.setVisibility(View.GONE);  
  202.             }  
  203.             return convertView;  
  204.         }  
  205.     }  
  206.   
  207.     /** 
  208.      * 提取英文的首字母,非英文字母用#代替。 
  209.      *  
  210.      * @param str 
  211.      * @return 
  212.      */  
  213.     private String getAlpha(String str) {  
  214.         if (str == null) {  
  215.             return "#";  
  216.         }  
  217.   
  218.         if (str.trim().length() == 0) {  
  219.             return "#";  
  220.         }  
  221.   
  222.         char c = str.trim().substring(01).charAt(0);  
  223.         // 正則表達式,判斷首字母是否是英文字母  
  224.         Pattern pattern = Pattern.compile("^[A-Za-z]+$");  
  225.         if (pattern.matcher(c + "").matches()) {  
  226.             return (c + "").toUpperCase(); // 大寫輸出  
  227.         } else {  
  228.             return "#";  
  229.         }  
  230.     }  
  231. }  

2.QuickAlphabeticBar.java

[java] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. package com.zhf.FastContactSearchWithAlphabeticBarDemo;  
  2.   
  3. import java.util.HashMap;  
  4. import com.zhf.FastContactSearchDemo.R;  
  5. import android.app.Activity;  
  6. import android.content.Context;  
  7. import android.os.Handler;  
  8. import android.util.AttributeSet;  
  9. import android.view.MotionEvent;  
  10. import android.view.View;  
  11. import android.widget.ImageButton;  
  12. import android.widget.ListView;  
  13. import android.widget.TextView;  
  14. /** 
  15.  * 字母表 
  16.  * @author [email protected] 
  17.  * 
  18.  */  
  19. public class QuickAlphabeticBar extends ImageButton {  
  20.     private TextView mDialogText;  
  21.     private Handler mHandler;  
  22.     private ListView mList;  
  23.     private float mHight;  
  24.     private String[] letters = new String[] { "#""A""B""C""D""E",  
  25.             "F""G""H""I""J""K""L""M""N""O""P""Q""R",  
  26.             "S""T""U""V""W""X""Y""Z" };  
  27.     private HashMap<String, Integer> alphaIndexer;  
  28.   
  29.     public QuickAlphabeticBar(Context context) {  
  30.         super(context);  
  31.     }  
  32.   
  33.     public QuickAlphabeticBar(Context context, AttributeSet attrs) {  
  34.         super(context, attrs);  
  35.     }  
  36.   
  37.     public QuickAlphabeticBar(Context context, AttributeSet attrs, int defStyle) {  
  38.         super(context, attrs, defStyle);  
  39.     }  
  40.   
  41.     public void init(Activity ctx) {  
  42.         mDialogText = (TextView) ctx.findViewById(R.id.fast_position);  
  43.         mDialogText.setVisibility(View.INVISIBLE);  
  44.         mHandler = new Handler();  
  45.     }  
  46.   
  47.     public void setListView(ListView mList) {  
  48.         this.mList = mList;  
  49.     }  
  50.   
  51.     public void setAlphaIndexer(HashMap<String, Integer> alphaIndexer) {  
  52.         this.alphaIndexer = alphaIndexer;  
  53.     }  
  54.       
  55.     public void setHight(float mHight) {  
  56.         this.mHight = mHight;  
  57.     }  
  58.   
  59.     @Override  
  60.     public boolean onTouchEvent(MotionEvent event) {  
  61.         int act = event.getAction();  
  62.         float y = event.getY();  
  63.         // 計算手指位置,找到對應的段,讓mList移動段開頭的位置上  
  64.         int selectIndex = (int) (y / (mHight / 27));  
  65.         if (selectIndex < 27) {// 防止越界  
  66.             String key = letters[selectIndex];  
  67.             if (alphaIndexer.containsKey(key)) {  
  68.                 int pos = alphaIndexer.get(key);  
  69.                 if (mList.getHeaderViewsCount() > 0) {// 防止ListView有標題欄,本例中沒有。  
  70.                     this.mList.setSelectionFromTop(  
  71.                             pos + mList.getHeaderViewsCount(), 0);  
  72.                 } else {  
  73.                     this.mList.setSelectionFromTop(pos, 0);  
  74.                 }  
  75.                 mDialogText.setText(letters[selectIndex]);  
  76.             }  
  77.         }  
  78.         if (act == MotionEvent.ACTION_DOWN) {  
  79.             if (mHandler != null) {  
  80.                 mHandler.post(new Runnable() {  
  81.                     @Override  
  82.                     public void run() {  
  83.                         if (mDialogText != null  
  84.                                 && mDialogText.getVisibility() == View.INVISIBLE) {  
  85.                             mDialogText.setVisibility(VISIBLE);  
  86.                         }  
  87.                     }  
  88.                 });  
  89.             }  
  90.         } else if (act == MotionEvent.ACTION_UP) {  
  91.             if (mHandler != null) {  
  92.                 mHandler.post(new Runnable() {  
  93.                     @Override  
  94.                     public void run() {  
  95.                         if (mDialogText != null  
  96.                                 && mDialogText.getVisibility() == View.VISIBLE) {  
  97.                             mDialogText.setVisibility(INVISIBLE);  
  98.                         }  
  99.                     }  
  100.                 });  
  101.             }  
  102.         }  
  103.         return super.onTouchEvent(event);  
  104.     }  
  105. }  

3.佈局文件

  3.1.main.xml

[java] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <RelativeLayout android:layout_width="fill_parent"  
  3.         xmlns:android="http://schemas.android.com/apk/res/android"  
  4.         android:layout_height="fill_parent" android:layout_weight="1.0">  
  5.     <ListView android:id="@+id/listView"  
  6.         android:layout_width="fill_parent"  
  7.         android:layout_height="fill_parent"  
  8.         android:scrollbars="none"  
  9.         android:layout_weight="1.0"  
  10.         android:scrollingCache="true"  
  11.         >  
  12.     </ListView>  
  13.     <com.zhf.FastContactSearchWithAlphabeticBarDemo.QuickAlphabeticBar  
  14.         android:layout_alignRight="@id/listView"  
  15.         android:layout_gravity="top|right|center"  
  16.         android:layout_marginTop="10dip"  
  17.         android:id="@+id/fast_scroller" android:background="@null"  
  18.         android:layout_width="wrap_content" android:layout_height="wrap_content"  
  19.         android:scaleType="centerInside"  
  20.         android:src="@drawable/dic_background" />  
  21.     <TextView  
  22.         android:layout_centerInParent="true"   
  23.         android:id="@+id/fast_position" android:textSize="48dip" android:visibility="invisible"  
  24.         android:textColor="#404040" android:background="@drawable/sort_icon_bg_click"  
  25.         android:layout_gravity="center_horizontal|top" android:padding="2dip"  
  26.         android:layout_margin="34dip" android:layout_width="70dip"  
  27.         android:layout_height="70dip" android:gravity="center" />  
  28. </RelativeLayout>  

  3.2.list_item.xml

[java] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="match_parent" >  
  5.       
  6.     <!-- 首字母 -->  
  7.     <TextView  
  8.         android:id="@+id/alpha"  
  9.         android:layout_width="fill_parent"  
  10.         android:layout_height="wrap_content"  
  11.         android:background="#333333"  
  12.         android:paddingLeft="10dip"  
  13.         android:textColor="#FFFFFF"  
  14.         android:visibility="gone" />  
  15.       
  16.     <!-- 聯繫人信息 -->  
  17.     <ImageView  
  18.         android:id="@+id/imageView"  
  19.         android:layout_width="wrap_content"  
  20.         android:layout_height="wrap_content"  
  21.         android:layout_alignParentLeft="true"  
  22.         android:layout_below="@id/alpha"  
  23.         android:src="@drawable/ic_launcher" />  
  24.   
  25.     <TextView  
  26.         android:id="@+id/name"  
  27.         android:layout_width="wrap_content"  
  28.         android:layout_height="wrap_content"  
  29.         android:layout_alignTop="@id/imageView"  
  30.         android:layout_marginLeft="2.0dip"  
  31.         android:layout_marginRight="5.0dip"  
  32.         android:layout_marginTop="6.0dip"  
  33.         android:layout_toRightOf="@id/imageView"  
  34.         android:singleLine="true"  
  35.         android:textAppearance="?android:textAppearanceMedium" />  
  36.   
  37.     <TextView  
  38.         android:id="@+id/number"  
  39.         android:layout_width="wrap_content"  
  40.         android:layout_height="wrap_content"  
  41.         android:layout_alignLeft="@id/name"  
  42.         android:layout_alignWithParentIfMissing="true"  
  43.         android:layout_below="@id/name"  
  44.         android:ellipsize="marquee"  
  45.         android:singleLine="true"  
  46.         android:textAppearance="?android:textAppearanceSmall" />  
  47.   
  48. </RelativeLayout>  

dic_background.xml

<?xml version="1.0" encoding="UTF-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" android:drawable="@drawable/a_z_click" />
<item android:state_focused="true" android:state_enabled="true"
android:drawable="@drawable/a_z_click" />
<item android:state_enabled="true" android:drawable="@drawable/a_z" />
</selector>

4.效果圖


源碼地址:http://download.csdn.net/detail/zhf198909/4485281


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章