Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發實例 >> Android實現聯系人字母表快速滾動

Android實現聯系人字母表快速滾動

編輯:Android開發實例

在上一篇文章中,我和大家一起實現了類似於Android系統聯系人的分組導航和擠壓動畫功能,本篇文章我將帶領大家在上篇文章的代碼基礎上改進,加入快速滾動功能。

如果還沒有看過我上一篇文章,請抓緊去閱讀一下 http://www.fengfly.com/plus/view-215093-1.html

其實ListView本身是有一個快速滾動屬性的,可以通過在XML中設置android:fastScrollEnabled="true"來啟用。包括以前老版本的Android聯系人中都是使用這種方式來進行快速滾動的。效果如下圖所示:
 

                                         
 

不過這種快速滾動方式比較丑陋,到後來很多手機廠商在定制自己ROM的時候都將默認快速滾動改成了類似iPhone上A-Z字母表快速滾動的方式。這裡我們怎麼能落後於時代的潮流呢!我們的快速滾動也要使用A-Z字母表的方式!

下面就來開始實現,首先打開上次的ContactsDemo工程,修改activity_main.xml布局文件。由於我們要在界面上加入字母表,因此我們需要一個Button,將這個Button的背景設為一張A-Z排序的圖片,然後居右對齊。另外還需要一個TextView,用於在彈出式分組布局上顯示當前的分組,默認是gone掉的,只有手指在字母表上滑動時才讓它顯示出來。修改後的布局文件代碼如下:

  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
  2.     xmlns:tools="http://schemas.android.com/tools" 
  3.     android:layout_width="match_parent" 
  4.     android:layout_height="match_parent" 
  5.     android:orientation="vertical" > 
  6.  
  7.     <ListView 
  8.         android:id="@+id/contacts_list_view" 
  9.         android:layout_width="fill_parent" 
  10.         android:layout_height="wrap_content" 
  11.         android:layout_alignParentTop="true" 
  12.         android:scrollbars="none" 
  13.         android:fadingEdge="none" > 
  14.     </ListView> 
  15.  
  16.     <LinearLayout 
  17.         android:id="@+id/title_layout" 
  18.         android:layout_width="fill_parent" 
  19.         android:layout_height="18dip" 
  20.         android:layout_alignParentTop="true" 
  21.         android:background="#303030" > 
  22.  
  23.         <TextView 
  24.             android:id="@+id/title" 
  25.             android:layout_width="wrap_content" 
  26.             android:layout_height="wrap_content" 
  27.             android:layout_gravity="center_horizontal" 
  28.             android:layout_marginLeft="10dip" 
  29.             android:textColor="#ffffff" 
  30.             android:textSize="13sp" /> 
  31.     </LinearLayout> 
  32.       
  33.     <Button   
  34.         android:id="@+id/alphabetButton" 
  35.         android:layout_width="wrap_content" 
  36.         android:layout_height="fill_parent" 
  37.         android:layout_alignParentRight="true" 
  38.         android:background="@drawable/a_z" 
  39.         /> 
  40.       
  41.     <RelativeLayout   
  42.         android:id="@+id/section_toast_layout" 
  43.         android:layout_width="70dip" 
  44.         android:layout_height="70dip" 
  45.         android:layout_centerInParent="true" 
  46.         android:background="@drawable/section_toast" 
  47.         android:visibility="gone" 
  48.         > 
  49.         <TextView   
  50.             android:id="@+id/section_toast_text" 
  51.             android:layout_width="wrap_content" 
  52.             android:layout_height="wrap_content" 
  53.             android:layout_centerInParent="true" 
  54.             android:textColor="#fff" 
  55.             android:textSize="30sp" 
  56.             /> 
  57.     </RelativeLayout> 
  58.  
  59. </RelativeLayout> 

然後打開MainActivity進行修改,毫無疑問,我們需要對字母表按鈕的touch事件進行監聽,於是在MainActivity中新增如下代碼:

  1. private void setAlpabetListener() {  
  2.     alphabetButton.setOnTouchListener(new OnTouchListener() {  
  3.         @Override 
  4.         public boolean onTouch(View v, MotionEvent event) {  
  5.             float alphabetHeight = alphabetButton.getHeight();  
  6.             float y = event.getY();  
  7.             int sectionPosition = (int) ((y / alphabetHeight) / (1f / 27f));  
  8.             if (sectionPosition < 0) {  
  9.                 sectionPosition = 0;  
  10.             } else if (sectionPosition > 26) {  
  11.                 sectionPosition = 26;  
  12.             }  
  13.             String sectionLetter = String.valueOf(alphabet.charAt(sectionPosition));  
  14.             int position = indexer.getPositionForSection(sectionPosition);  
  15.             switch (event.getAction()) {  
  16.             case MotionEvent.ACTION_DOWN:  
  17.                 alphabetButton.setBackgroundResource(R.drawable.a_z_click);  
  18.                 sectionToastLayout.setVisibility(View.VISIBLE);  
  19.                 sectionToastText.setText(sectionLetter);  
  20.                 contactsListView.setSelection(position);  
  21.                 break;  
  22.             case MotionEvent.ACTION_MOVE:  
  23.                 sectionToastText.setText(sectionLetter);  
  24.                 contactsListView.setSelection(position);  
  25.                 break;  
  26.             default:  
  27.                 alphabetButton.setBackgroundResource(R.drawable.a_z);  
  28.                 sectionToastLayout.setVisibility(View.GONE);  
  29.             }  
  30.             return true;  
  31.         }  
  32.     });  
  33. }  

可以看到,在這個方法中我們注冊了字母表按鈕的onTouch事件,然後在onTouch方法裡做了一些邏輯判斷和處理,下面我來一一詳細說明。首先通過字母表按鈕的getHeight方法獲取到字母表的總高度,然後用event.getY方法獲取到目前手指在字母表上的縱坐標,用縱坐標除以總高度就可以得到一個用小數表示的當前手指所在位置(0表在#端,1表示在Z端)。由於我們的字母表中一共有27個字符,再用剛剛算出的小數再除以1/27就可以得到一個0到27范圍內的浮點數,之後再把這個浮點數向下取整,就可以算出我們當前按在哪個字母上了。然後再對event的action進行判斷,如果是ACTION_DOWN或ACTION_MOVE,就在彈出式分組上顯示當前手指所按的字母,並調用ListView的setSelection方法把列表滾動到相應的分組。如果是其它的action,就將彈出式分組布局隱藏。
MainActivity的完整代碼如下:

  1. public class MainActivity extends Activity {  
  2.  
  3.     /**  
  4.      * 分組的布局  
  5.      */ 
  6.     private LinearLayout titleLayout;  
  7.  
  8.     /**  
  9.      * 彈出式分組的布局  
  10.      */ 
  11.     private RelativeLayout sectionToastLayout;  
  12.  
  13.     /**  
  14.      * 右側可滑動字母表  
  15.      */ 
  16.     private Button alphabetButton;  
  17.  
  18.     /**  
  19.      * 分組上顯示的字母  
  20.      */ 
  21.     private TextView title;  
  22.  
  23.     /**  
  24.      * 彈出式分組上的文字  
  25.      */ 
  26.     private TextView sectionToastText;  
  27.  
  28.     /**  
  29.      * 聯系人ListView  
  30.      */ 
  31.     private ListView contactsListView;  
  32.  
  33.     /**  
  34.      * 聯系人列表適配器  
  35.      */ 
  36.     private ContactAdapter adapter;  
  37.  
  38.     /**  
  39.      * 用於進行字母表分組  
  40.      */ 
  41.     private AlphabetIndexer indexer;  
  42.  
  43.     /**  
  44.      * 存儲所有手機中的聯系人  
  45.      */ 
  46.     private List<Contact> contacts = new ArrayList<Contact>();  
  47.  
  48.     /**  
  49.      * 定義字母表的排序規則  
  50.      */ 
  51.     private String alphabet = "#ABCDEFGHIJKLMNOPQRSTUVWXYZ";  
  52.  
  53.     /**  
  54.      * 上次第一個可見元素,用於滾動時記錄標識。  
  55.      */ 
  56.     private int lastFirstVisibleItem = -1;  
  57.  
  58.     @Override 
  59.     protected void onCreate(Bundle savedInstanceState) {  
  60.         super.onCreate(savedInstanceState);  
  61.         setContentView(R.layout.activity_main);  
  62.         adapter = new ContactAdapter(this, R.layout.contact_item, contacts);  
  63.         titleLayout = (LinearLayout) findViewById(R.id.title_layout);  
  64.         sectionToastLayout = (RelativeLayout) findViewById(R.id.section_toast_layout);  
  65.         title = (TextView) findViewById(R.id.title);  
  66.         sectionToastText = (TextView) findViewById(R.id.section_toast_text);  
  67.         alphabetButton = (Button) findViewById(R.id.alphabetButton);  
  68.         contactsListView = (ListView) findViewById(R.id.contacts_list_view);  
  69.         Uri uri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;  
  70.         Cursor cursor = getContentResolver().query(uri,  
  71.                 new String[] { "display_name", "sort_key" }, null, null, "sort_key");  
  72.         if (cursor.moveToFirst()) {  
  73.             do {  
  74.                 String name = cursor.getString(0);  
  75.                 String sortKey = getSortKey(cursor.getString(1));  
  76.                 Contact contact = new Contact();  
  77.                 contact.setName(name);  
  78.                 contact.setSortKey(sortKey);  
  79.                 contacts.add(contact);  
  80.             } while (cursor.moveToNext());  
  81.         }  
  82.         startManagingCursor(cursor);  
  83.         indexer = new AlphabetIndexer(cursor, 1, alphabet);  
  84.         adapter.setIndexer(indexer);  
  85.         if (contacts.size() > 0) {  
  86.             setupContactsListView();  
  87.             setAlpabetListener();  
  88.         }  
  89.     }  
  90.  
  91.     /**  
  92.      * 為聯系人ListView設置監聽事件,根據當前的滑動狀態來改變分組的顯示位置,從而實現擠壓動畫的效果。  
  93.      */ 
  94.     private void setupContactsListView() {  
  95.         contactsListView.setAdapter(adapter);  
  96.         contactsListView.setOnScrollListener(new OnScrollListener() {  
  97.             @Override 
  98.             public void onScrollStateChanged(AbsListView view, int scrollState) {  
  99.             }  
  100.  
  101.             @Override 
  102.             public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,  
  103.                     int totalItemCount) {  
  104.                 int section = indexer.getSectionForPosition(firstVisibleItem);  
  105.                 int nextSecPosition = indexer.getPositionForSection(section + 1);  
  106.                 if (firstVisibleItem != lastFirstVisibleItem) {  
  107.                     MarginLayoutParams params = (MarginLayoutParams) titleLayout.getLayoutParams();  
  108.                     params.topMargin = 0;  
  109.                     titleLayout.setLayoutParams(params);  
  110.                     title.setText(String.valueOf(alphabet.charAt(section)));  
  111.                 }  
  112.                 if (nextSecPosition == firstVisibleItem + 1) {  
  113.                     View childView = view.getChildAt(0);  
  114.                     if (childView != null) {  
  115.                         int titleHeight = titleLayout.getHeight();  
  116.                         int bottom = childView.getBottom();  
  117.                         MarginLayoutParams params = (MarginLayoutParams) titleLayout  
  118.                                 .getLayoutParams();  
  119.                         if (bottom < titleHeight) {  
  120.                             float pushedDistance = bottom - titleHeight;  
  121.                             params.topMargin = (int) pushedDistance;  
  122.                             titleLayout.setLayoutParams(params);  
  123.                         } else {  
  124.                             if (params.topMargin != 0) {  
  125.                                 params.topMargin = 0;  
  126.                                 titleLayout.setLayoutParams(params);  
  127.                             }  
  128.                         }  
  129.                     }  
  130.                 }  
  131.                 lastFirstVisibleItem = firstVisibleItem;  
  132.             }  
  133.         });  
  134.  
  135.     }  
  136.  
  137.     /**  
  138.      * 設置字母表上的觸摸事件,根據當前觸摸的位置結合字母表的高度,計算出當前觸摸在哪個字母上。  
  139.      * 當手指按在字母表上時,展示彈出式分組。手指離開字母表時,將彈出式分組隱藏。  
  140.      */ 
  141.     private void setAlpabetListener() {  
  142.         alphabetButton.setOnTouchListener(new OnTouchListener() {  
  143.             @Override 
  144.             public boolean onTouch(View v, MotionEvent event) {  
  145.                 float alphabetHeight = alphabetButton.getHeight();  
  146.                 float y = event.getY();  
  147.                 int sectionPosition = (int) ((y / alphabetHeight) / (1f / 27f));  
  148.                 if (sectionPosition < 0) {  
  149.                     sectionPosition = 0;  
  150.                 } else if (sectionPosition > 26) {  
  151.                     sectionPosition = 26;  
  152.                 }  
  153.                 String sectionLetter = String.valueOf(alphabet.charAt(sectionPosition));  
  154.                 int position = indexer.getPositionForSection(sectionPosition);  
  155.                 switch (event.getAction()) {  
  156.                 case MotionEvent.ACTION_DOWN:  
  157.                     alphabetButton.setBackgroundResource(R.drawable.a_z_click);  
  158.                     sectionToastLayout.setVisibility(View.VISIBLE);  
  159.                     sectionToastText.setText(sectionLetter);  
  160.                     contactsListView.setSelection(position);  
  161.                     break;  
  162.                 case MotionEvent.ACTION_MOVE:  
  163.                     sectionToastText.setText(sectionLetter);  
  164.                     contactsListView.setSelection(position);  
  165.                     break;  
  166.                 default:  
  167.                     alphabetButton.setBackgroundResource(R.drawable.a_z);  
  168.                     sectionToastLayout.setVisibility(View.GONE);  
  169.                 }  
  170.                 return true;  
  171.             }  
  172.         });  
  173.     }  
  174.  
  175.     /**  
  176.      * 獲取sort key的首個字符,如果是英文字母就直接返回,否則返回#。  
  177.      *   
  178.      * @param sortKeyString  
  179.      *            數據庫中讀取出的sort key  
  180.      * @return 英文字母或者#  
  181.      */ 
  182.     private String getSortKey(String sortKeyString) {  
  183.         alphabetButton.getHeight();  
  184.         String key = sortKeyString.substring(0, 1).toUpperCase();  
  185.         if (key.matches("[A-Z]")) {  
  186.             return key;  
  187.         }  
  188.         return "#";  
  189.     }  
  190.  
  191. }  

好了,就改動了以上兩處,其它文件都保持不變,讓我們來運行一下看看效果:
 

 

                                   
 

非常不錯!當你的手指在右側字母表上滑動時,聯系人的列表也跟著相應的變動,並在屏幕中央顯示一個當前的分組。

現在讓我們回數一下,分組導航、擠壓動畫、字母表快速滾動,Android系統聯系人全特效都實現了!

 

源碼下載,請點擊這裡

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved