Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android開發系列(十三) QQ聯系人列表完整版——ExpandableListView高階使用方法

Android開發系列(十三) QQ聯系人列表完整版——ExpandableListView高階使用方法

編輯:關於Android編程

  前兩天電腦壞掉了,導致這一兩天沒有更新。發現之前寫的幾篇博客浏覽量已經接近1000,有種受寵若驚的感覺,寫這個系列的博客主要是假期想干一些平時沒有時間做的興趣愛好,並把自己的一點一滴記錄下來。這一段時間由於各種原因以致於更新速度很慢,之前的打算是先把QQ2013的Activity的布局搭建出來,然後再設計其中的核心代碼,如網絡編程,搭建一個小型服務器,進而實現QQ基本的功能,從現在的進度來看這個計劃可能完不成了。不過我仍然會繼續做這個項目,相信就算不會徹底完成也能夠搭出漂亮的QQ框架來。     進入正題。上一節結束時提到QQ聯系人列表界面還有一個效果沒有實現,這個效果是當聯系人一級條目滑動到屏幕的頂端時,該一級條目就會懸停在屏幕的頂端,當往下拉時又會隨著ExpandableListView的Item正常移動,如官方效果圖圖所示:         注意觀察“我的好友”那一欄,本節實現的即上述效果。   首先講一下思路:     1、不能使用onScroll()方法,這一方法會在ExpandableListView展開的時候調用,至於其調用的周期並不是太明確,但可以確定的是onScroll並不能直接實現上述效果。                   2、這裡應該獲得ScrollView的實例(findViewById方法),然後調用setOnTouch()方法,在setOnTouch()方法中進一步進行設置。     3、這裡的基本思路是:當拖動屏幕時,setOnTouch方法被調用,在該方法中開辟一個子線程,這個子線程用於檢測屏幕中的ScrollView對象是否仍在運動,直到不再拖動屏幕或者屏幕上的控件在慣性的作用下運動至停止時,該線程才會自動終結。在該線程中判斷一級條目(這裡用groupItem表示)是否向上滾出了屏幕。     4、在該Activity的主布局文件中ScrollView的後面添加一個LinearLayout控件,該控件的布局和GroupItem的布局文件的內容是一樣的,將其位置設置為至於屏幕(父控件)的頂端,平時設置其Visibility為View.GONE 不可見不可操作狀態,當某一個已經展開(expanded)的groupItem滾出了屏幕時,就將該隱藏的控件設置為可見,並將其內容設置為和剛剛滾出屏幕的groupItem的內容一摸一樣。若所有的groupItem都為滑出屏幕,那麼將該控件重新設置為不可見(GONE);     5、本節中遇見的最大的障礙就是我沒有找到獲得每一個groupItem在屏幕上的實時位置的方法,所以這裡對原來的groupData對象做了修改,在HashMap對象中新添加了一個鍵值對 key="location"  value= 該groupItem在ExpandableListView中的相對縱坐標。在後在上面創建的坐標檢測子線程中獲得groupData中存放的groupItem的相對坐標再加上ExpandableListView的絕對縱坐標,然後判斷groupItem是否滑出了屏幕,進而對“隱藏控件”執行相應的操作。注意這裡應該先判斷groupPosition靠後的groupItem的坐標,懸停的控件顯示的是最後滑出屏幕的groupItem的信息。     6、本節將Activity的標題去掉了,去掉的方法是在onCreate()方法中 setContentView之前(必須是之前)調用requestWindowFeature(Window.FEATURE_NO_TITLE);     7、本節中需要在子線程中修改MainActivity 安卓UI,而直接修改是不允許的,所以需要使用一個自定義的Handler對象,調用父類的構造方法         public MyHandler(Looper looper){                            super(looper);         }             並復寫handleMessage()方法修改MainActivity的UI。             關於Android消息處理機制我目前不想再多講,做開發的話夠用就行,沒必要掌握的太徹底,如果想對Handler有一個比較好的了解,可以參考:             http://blog.csdn.net/zkdemon/article/details/6914161      8、ExpandableListView可以調用collapseGroup(int groupPosition)或者ExpandGroup(int groupPosition)強制的關閉或者展開一個Group。這對於實現懸浮控件的點擊事件具有重要作用!     鑒於代碼量越來越多了,這裡先把修改的地方列出來:   主布局文件:   復制代碼 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"     xmlns:tools="http://schemas.android.com/tools"     android:layout_width="match_parent"     android:layout_height="match_parent"     android:background="#f1f1f1"     tools:context=".MainActivity"     android:scrollbars="vertical"     android:scrollbarAlwaysDrawVerticalTrack="true" >                 <ScrollView          android:id="@+id/qqlist_scroll"         android:layout_width="match_parent"         android:layout_height="wrap_content"         android:fadingEdge="none">         <LinearLayout              android:layout_width="match_parent"             android:layout_height="wrap_content"             android:orientation="vertical">                          <ListView                  android:id="@+id/qqlist_classify"                 android:layout_width="match_parent"                 android:layout_height="wrap_content"                 android:divider="#000000"                 android:dividerHeight="0px"                 android:fadingEdge="none"/>             <TextView                  android:layout_width="match_parent"                 android:layout_height="wrap_content"                 android:background="@drawable/qqlist_classify_text"                 android:text="好友分組"                 android:textSize="6pt"                 android:textColor="#666666"                 android:padding="4dip"/>                          <ExpandableListView                  android:id="@+id/qq_list"                 android:layout_width="match_parent"                 android:layout_height="wrap_content"                 android:divider="#888888"                 android:dividerHeight="0px"                 android:fadingEdge="none"/>                          <TextView                  android:layout_width="match_parent"                 android:layout_height="wrap_content"                 android:background="@drawable/qqlist_classify_text"                 android:text="生活服務"                 android:textSize="6pt"                 android:textColor="#666666"                 android:padding="4dip"/>                          <ListView                  android:id="@+id/qqlist_classify_down"                 android:layout_width="match_parent"                 android:layout_height="wrap_content"                 android:divider="#000000"                 android:dividerHeight="0px"/>                                   </LinearLayout>                       </ScrollView>     <LinearLayout          android:layout_width="match_parent"         android:layout_height="40dip"         android:id="@+id/titleGroupView"         android:orientation="horizontal"         android:visibility="gone"          android:background="@drawable/list_item_border">              <ImageView             android:id="@+id/title_groupImage"             android:layout_width="match_parent"             android:layout_height="16dip"             android:layout_weight="1.8"             android:layout_gravity="center"             android:background="@drawable/todown" />           <TextView             android:id="@+id/title_groupName"             android:layout_width="match_parent"             android:layout_height="42dip"             android:layout_weight="1"             android:paddingLeft="15dip"             android:paddingTop="11dip"             android:textSize="7pt"             android:text="fdg" />         <TextView              android:id="@+id/title_childCount"             android:layout_width="match_parent"             android:layout_height="42dip"             android:layout_weight="1"             android:gravity="right"             android:paddingRight="10dip"             android:paddingTop="11dip"             android:text="ewsf"/>       </LinearLayout>              </RelativeLayout> 復制代碼   展開或者關閉group時都會對每一個groupItem的縱坐標進行更新。   復制代碼 @Override         public void onGroupExpanded(int groupPosition) {             // TODO Auto-generated method stub             super.onGroupExpanded(groupPosition);                        /**              * 更新groupItem的相對坐標              */             groupData.get(groupPosition).put("expanded", true);             for(int i=groupPosition+1; i<groupData.size(); i++){                 groupData.get(i).put("location",(Integer)groupData.get(i).get("location")+childData.get(groupPosition).size()*CHILD_HEIGHT );             }                          float deviationFix=0;         //對ExpandableListView高度的誤差修正             for(int i=0;i<groupData.size() ;i++){                 deviationFix +=(Integer)groupData.get(i).get("location")/CHILD_HEIGHT*0.5;             }                          height+=childData.get(groupPosition).size()*CHILD_HEIGHT;             ViewGroup.LayoutParams  params= exListView.getLayoutParams();             params.height=height-floatToInt(deviationFix);             exListView.setLayoutParams(params);                                                }           @Override         public void onGroupCollapsed(int groupPosition) {             // TODO Auto-generated method stub             super.onGroupCollapsed(groupPosition);             height=height-childData.get(groupPosition).size()*CHILD_HEIGHT;             ViewGroup.LayoutParams  params= exListView.getLayoutParams();             params.height=height;             exListView.setLayoutParams(params);                          /**              * 更新groupItem的相對坐標              */             groupData.get(groupPosition).put("expanded", false);             for(int i=groupPosition+1; i<groupData.size(); i++){                 groupData.get(i).put("location",(Integer)groupData.get(i).get("location")-childData.get(groupPosition).size()*CHILD_HEIGHT );             }         } 復制代碼   對ScrollView設置監聽器:    復制代碼 qqScroll.setOnTouchListener(new OnTouchListener() {                          @Override             public boolean onTouch(View v, MotionEvent event) {                 // TODO Auto-generated method stub                 if(event.getAction()==MotionEvent.ACTION_MOVE && isChecking==false){                     new LocationCheckThread().start();                 }                 return false;             }         }); 復制代碼 坐標檢測線程:   復制代碼 /**      * 實現這個Activity的最後一個效果,即滑動到某一個Group那麼改GroupItem就在屏幕頂端懸停的效果      * 方法:需要使用onTouchEvent方法,這個比用onScrollView方法靠譜      */     private boolean isChecking=false;               private class LocationCheckThread extends Thread{           @Override         public void run() {             // TODO Auto-generated method stub             super.run();             isChecking=true;             int[] location=new int[2];             int beforeY=0;             int i;             ExpandableHandler mHandler=new ExpandableHandler(Looper.getMainLooper());             while(true){                 //exListView.getLocationOnScreen(location);                                    exListView.getLocationOnScreen(location);                 if(beforeY==location[1]){                    //控件停止運動,線程關閉                     isChecking=false;                     return;                 }                 else{                     beforeY=location[1];                     for(i=groupData.size()-1; i>=0; i--){                         if((Boolean)groupData.get(i).get("expanded")&&(Integer)groupData.get(i).get("location")+location[1]<=24){                                                            Message msg=new Message();                             msg.arg1=childData.get(i).size();                             msg.arg2=i;                             msg.obj=groupData.get(i).get("groupName");                             msg.what=VISIBILITY_VISIBLE;                             mHandler.sendMessage(msg);                             break;                         }                     }                     if(i<0){                         Message msg=new Message();                         msg.what=VISIBILITY_GONE;                         msg.obj="";                  //必須加這一步,否則會有空指針異常                         mHandler.sendMessage(msg);                     }                                      }                   try {                     this.sleep(80);         //sleep的時間不能過短!!                 } catch (InterruptedException e) {                     // TODO Auto-generated catch block                     e.printStackTrace();                 }                              }                      }          } 復制代碼   在線程中判斷GroupItem是否有滑動出屏幕的,創建Message對象,綁定響應的groupItem的信息(position,Name,childCount,是否顯示Visibility),然後由Handler對象發出[sendMessage();] 注意sleep的時間不能過短,因為當手指不再脫離屏幕而ListView 自由滑動時,由於滑動的速度較慢,導致兩次檢測坐標是結果一樣,從而意外的終止線程。   isChecking是boolean型數據,標記線程工作的狀態,避免在滑動的過程中同時開辟多個子線程產生異常。       然後是MyHandler類:   復制代碼 public class ExpandableHandler extends Handler{           public ExpandableHandler(Looper looper){             super(looper);         }         @Override         public void handleMessage(Message msg) {             // TODO Auto-generated method stub             super.handleMessage(msg);             int listNum=msg.arg1;             int visibility=msg.what;             int groupPos=msg.arg2;             String groupName=msg.obj.toString();                          if(visibility==VISIBILITY_GONE){                 titleGroupView.setVisibility(View.GONE);                                  return;             }             else{                   titleGroupView.setVisibility(View.VISIBLE);                 titleGroupName.setText(groupName);                 titleChildCount.setText(""+listNum);                                  titleGroupView.setTag(groupPos);        //給這個View控件設置一個標簽屬性,用於存放groupPosition                 /**                  * setText()中的參數不能使int型!!                  */             }                      }              } 復制代碼   創建MyHandler對象,在其中復寫handleMessage();方法,在該方法中設置懸浮控件的顯示效果(更新系統UI)   最後還需要實現一個效果,當懸浮控件出現時,點擊懸浮控件,會把該控件對應的groupItem關掉(collapseGroup),因此需要設置一個點擊監聽器:   復制代碼 titleGroupView.setOnClickListener(new OnClickListener(){               @Override             public void onClick(View v) {                 // TODO Auto-generated method stub                 int groupPosition=(Integer)titleGroupView.getTag();                   exListView.collapseGroup(groupPosition);                                  new LocationCheckThread().start();                                               }                      }); 復制代碼   注意這裡又一次啟動了坐標檢測線程,是因為需要在調用collapseGroup之後對系統的UI做一次刷新,避免產生顯示異常。    
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved