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


  前兩天電腦壞掉了,導致這一兩天沒有更新。發現之前寫的幾篇博客瀏覽量已經接近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做一次刷新,避免產生顯示異常。

 

以上就是主要需要修改的地方,然后附上整個Activity的代碼:

代碼太多折疊起來了:

package com.dragon.android_qq;


import android.location.Location;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.app.Activity;
import android.content.Context;
import android.view.DragEvent;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnDragListener;
import android.view.View.OnTouchListener;
import android.view.ViewGroup;
import android.view.View.OnClickListener;
import android.view.ViewGroup.LayoutParams;
import android.view.Window;
import android.view.WindowManager;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.BaseAdapter;
import android.widget.BaseExpandableListAdapter;
import android.widget.ExpandableListAdapter;
import android.widget.ExpandableListView;
import android.widget.ExpandableListView.OnGroupClickListener;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.Toast;

import java.util.*;

import com.dragon.persondata.ContactsInfo;


  

public class ContactsListExpandable extends Activity {

    
    private int height=0;
    private  int GROUP_HEIGHT=0;
    private  int CHILD_HEIGHT=52;
    private int VISIBILITY_GONE=0;
    private int VISIBILITY_VISIBLE=1;
    int[] photoRes={R.drawable.contact_0,R.drawable.contact_1,R.drawable.contact_2,R.drawable.contact_3};
     
    String[] groupFrom={"groupImage","groupName","childCount"};
    int[] groupTo={R.id.groupImage,R.id.groupName,R.id.childCount};
    String[] childFrom={"userImage","userName","userSign"};
    int[] childTo={R.id.ct_photo,R.id.ct_name,R.id.ct_sign};
    ArrayList<HashMap<String,Object>> groupData=null;
    ArrayList<ArrayList<HashMap<String,Object>>> childData=null; 
    
    ArrayList<HashMap<String,Object>> groupItenformation=null;  //用於存放groupItem的相對位置
    
    int[] groupIndicator={R.drawable.toright,R.drawable.todown};
    ExpandableListView exListView=null;
    ListView listViewTop=null,listViewDown=null;
    ScrollView qqScroll=null;
    LinearLayout titleGroupView=null;
    ImageView titleImage=null;
    TextView titleGroupName=null;
    TextView titleChildCount=null;
    MyExpandableListViewAdapter adapter=null;
    
    
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);  
        setContentView(R.layout.layout_qqlist_expandable);
        groupData=new ArrayList<HashMap<String,Object>>();
        childData=new ArrayList<ArrayList<HashMap<String,Object>>> ();
        
        //創建groupLocation對象
        //groupItemInformation=new ArrayList<HashMap<String,Object>>();
        
        ContactsInfo user1=new ContactsInfo("暗夜之殤","總有一天會尋找到自己的幸福",R.drawable.contact_0,"我的好友");
        ContactsInfo user2=new ContactsInfo("街角的幸福","有些事終於想開了",R.drawable.contact_1,"我的好友");
        ContactsInfo user3=new ContactsInfo("憤怒的小胖","誰再叫我小胖我跟誰急!",R.drawable.contact_3,"朋友");
        ContactsInfo user4=new ContactsInfo("放羊的星星","What ever",R.drawable.contact_2,"陌生人");
        ContactsInfo user5=new ContactsInfo("都市麗人","我要我的完美",R.drawable.contact_4,"我的好友");
        
        addUser(user1);
        addUser(user2);
        addUser(user3);
        addUser(user4);
        addUser(user5);
        addUser(user1);
        addUser(user2);
        addUser(user3);
        addUser(user4);
        addUser(user5);
        addUser(user3);
        addUser(user4);
        addUser(user5);
        addUser(user3);
        addUser(user4);
        addUser(user5);
        
        
        
        
          
        //不能用HashMap的實參賦給Map形參,只能new一個HashMap對象賦給Map的引用!
        
        
        exListView=(ExpandableListView)findViewById(R.id.qq_list);
        adapter=new MyExpandableListViewAdapter(this,groupData,R.layout.layout_qqlist_group,groupFrom,groupTo,childData,R.layout.layout_qqlist_child,childFrom,childTo );
        exListView.setAdapter(adapter);
        exListView.setGroupIndicator(null);
        
        
        qqScroll=(ScrollView)findViewById(R.id.qqlist_scroll);
    
        
        
        
        
        
        
        View exGroupListItem= exListView.getExpandableListAdapter().getGroupView(0,false, null, exListView );
        exGroupListItem.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
        exGroupListItem.measure(0, 0);
        GROUP_HEIGHT=exGroupListItem.getMeasuredHeight();
        
        View exChildListItem=exListView.getExpandableListAdapter().getChildView(0, 0, false, null, exListView);
        exChildListItem.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT));
        exChildListItem.measure(0, 0);
        CHILD_HEIGHT=exChildListItem.getMeasuredHeight();
        
        ViewGroup.LayoutParams  params= exListView.getLayoutParams();
        height=groupData.size()*GROUP_HEIGHT-2;
        params.height=height;
        exListView.setLayoutParams(params);
        
        for(int i=0; i<groupData.size() ;i++){
            groupData.get(i).put("location",i*GROUP_HEIGHT);
        }
        
        /*
        
        for(int i=0; i<childData.size(); i++){
            HashMap<String,Object> map1=new HashMap<String,Object>();
            HashMap<String,Object> map2=new HashMap<String,Object>();
            map1.put("location", i*GROUP_HEIGHT);
            map1.put("expanded", false);
            groupItemInformation.add(map1);
        }
        */
        
        listViewTop=(ListView)findViewById(R.id.qqlist_classify);
        ArrayList<HashMap<String,Object>> listTop=new ArrayList<HashMap<String,Object>>();
        HashMap<String,Object> mapTop1=new HashMap<String,Object>();
        HashMap<String,Object> mapTop2=new HashMap<String,Object>();
        HashMap<String,Object> mapTop3=new HashMap<String,Object>();
        mapTop1.put("listTopImage",R.drawable.address_list);
        mapTop1.put("listTopText", "通訊錄");
        mapTop2.put("listTopImage",R.drawable.chat_flock);
        mapTop2.put("listTopText", "群");
        mapTop3.put("listTopImage",R.drawable.forum);
        mapTop3.put("listTopText", "討論組");
        listTop.add(mapTop1);
        listTop.add(mapTop2);
        listTop.add(mapTop3);
        MyListViewAdapter adapterTop=new MyListViewAdapter(this, listTop,
                R.layout.qqlist_classify_item, new String[]{"listTopImage","listTopText"}, new int[]{R.id.qqlist_classify_image,R.id.qqlist_classify_name});
        
        listViewTop.setAdapter(adapterTop);
        ViewGroup.LayoutParams paramsTop=listViewTop.getLayoutParams();
        View listItem=listViewTop.getAdapter().getView(0, null, listViewTop);
        listItem.measure(0, 0);
        paramsTop.height=3*listItem.getMeasuredHeight()-2;
        
        //ListView屬於一種ViewGroup類型
        listViewTop.setLayoutParams(paramsTop);
        
        /**
         * 創建一個String數組對象不能直接寫String[]{}  必須在前面加上new,即寫成 new String[]{"listTopImage","listTopText"}
         * 
         */
        
        listViewDown=(ListView)findViewById(R.id.qqlist_classify_down);
        ArrayList<HashMap<String,Object>> listDown=new ArrayList<HashMap<String,Object>>();
        HashMap<String,Object> mapDown1=new HashMap<String,Object>();
        mapDown1.put("listTopImage",R.drawable.life_service);
        mapDown1.put("listTopText", "生活服務");
        listDown.add(mapDown1);
        listTop.add(mapTop3);
        MyListViewAdapter adapterDown=new MyListViewAdapter(this, listDown,
                R.layout.qqlist_classify_item, new String[]{"listTopImage","listTopText"}, new int[]{R.id.qqlist_classify_image,R.id.qqlist_classify_name});
        
        listViewDown.setAdapter(adapterDown);
        
        
        
        titleGroupView=(LinearLayout)findViewById(R.id.titleGroupView);
        titleGroupName=(TextView)findViewById(R.id.title_groupName);
        titleChildCount=(TextView)findViewById(R.id.title_childCount);
        
        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();
                
                
            }
            
        });
        
        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();
                }
                
            }
            
        }
    
    }
    
    
    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型!!
                 */
            }
            
        }
        
    }

    protected void addUser(ContactsInfo user)
    {
        int i;
        for(i=0; i< groupData.size(); i++){
            if(groupData.get(i).get("groupName").toString().equals(user.groupInfo)){
                break;
            }
        }
        if(i>=groupData.size()){
            HashMap<String,Object> map=new HashMap<String,Object>();
            map.put("groupImage", groupIndicator);
            map.put("groupName",user.groupInfo );
            map.put("childCount", 0);
            groupData.add(map);
            
            ArrayList<HashMap<String,Object>> list=new ArrayList<HashMap<String,Object>>();
            childData.add(list);
        }
        
        HashMap<String,Object> userData=new HashMap<String,Object>();
        userData.put("userImage",user.userImage );
        userData.put("userName", user.userName);
        userData.put("userSign", user.userSign);
        childData.get(i).add(userData);
        Integer count=(Integer)groupData.get(i).get("childCount")+1;
        groupData.get(i).put("childCount", count);    
        groupData.get(i).put("expanded", false);

        
    }
    
    
    
    
    
    
    









    /**
     * ExpandableListView對應的適配器
     * @author DragonGN
     *
     */
    public class MyExpandableListViewAdapter extends BaseExpandableListAdapter{
        
        private Context context=null;
        private ArrayList<HashMap<String,Object>> groupData=null;
        int groupLayout=0;
        private String[] groupFrom=null;
        private int[] groupTo=null;
        private ArrayList<ArrayList<HashMap<String,Object>>> childData=null;
        int childLayout=0;
        private String[] childFrom=null;
        private int[] childTo=null;
        
        
        

        public MyExpandableListViewAdapter(Context context, ArrayList<HashMap<String, Object>> groupData,
                int groupLayout, String[] groupFrom, int[] groupTo,
                ArrayList<ArrayList<HashMap<String, Object>>> childData, int childLayout,
                String[] childFrom, int[] childTo) {
            super();
            this.context = context;
            this.groupData = groupData;
            this.groupLayout = groupLayout;
            this.groupFrom = groupFrom;
            this.groupTo = groupTo;
            this.childData = childData;
            this.childLayout = childLayout;
            this.childFrom = childFrom;
            this.childTo = childTo;
            
        }

        @Override
        public Object getChild(int arg0, int arg1) {
            // TODO Auto-generated method stub
            return null;
        }

        /**
         * position與id一樣,都是從0開始計數的,
         * 這里返回的id也是從0開始計數的
         */
        @Override
        public long getChildId(int groupPosition, int childPosition) {
            // TODO Auto-generated method stub
            long id=0;
            for(int i=0;i<groupPosition; i++){
                id+=childData.size();
            }
            id+=childPosition;  
            return id;           
        }
        
        /**ChildViewHolder內部類**/
        class ChildViewHolder{
            ImageButton userImage=null;
            TextView userName=null;
            TextView userSign=null;
        }
        
        /**頭像點擊事件監聽類**/
        class ImageClickListener implements OnClickListener{

            ChildViewHolder holder=null;
            public ImageClickListener(ChildViewHolder holder){
                this.holder=holder;
            }
            
            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                Toast.makeText(context, holder.userName.getText()+" is clicked", Toast.LENGTH_SHORT).show();
                
            }
            
        }

        
        
        @Override
        public View getChildView(int groupPosition, int childPosition,
                boolean isLastChild, View convertView, ViewGroup parent) {
            // TODO Auto-generated method stub
            /**
             * 這里isLastChild目前沒用到,如果出現異常再說
             */
            ChildViewHolder holder=null;
            if(convertView==null){
                convertView= LayoutInflater.from(context).inflate(childLayout,null);
                                             //感覺這里需要把root設置成ViewGroup 對象
                /**
                 * ERROR!!這里不能把null換成parent,否則會出現異常退出,原因不太確定,可能是inflate方法獲得的這個item的View
                 * 並不屬於某個控件組,所以使用默認值null即可
                 */
                holder=new ChildViewHolder();
                holder.userImage=(ImageButton)convertView.findViewById(childTo[0]);
                holder.userName=(TextView)convertView.findViewById(childTo[1]);
                holder.userSign=(TextView)convertView.findViewById(childTo[2]);
                convertView.setTag(holder);
            }
            else{
                holder=(ChildViewHolder)convertView.getTag();
            }
            
            holder.userImage.setBackgroundResource((Integer)(childData.get(groupPosition).get(childPosition).get(childFrom[0])));
            holder.userName.setText(childData.get(groupPosition).get(childPosition).get(childFrom[1]).toString());
            holder.userSign.setText(childData.get(groupPosition).get(childPosition).get(childFrom[2]).toString());
            holder.userImage.setOnClickListener(new ImageClickListener(holder));

            
            return convertView;
        }

        
        @Override
        public int getChildrenCount(int groupPosition) {
            // TODO Auto-generated method stub
            return childData.get(groupPosition).size();
        }

        @Override
        public Object getGroup(int groupPosition) {
            // TODO Auto-generated method stub
            return null;
        }

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

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

        
        class GroupViewHolder{
            ImageView image=null;
            TextView groupName=null;
            TextView childCount=null;
        }
        
        @Override
        public View getGroupView(int groupPosition, boolean isExpanded,
                View convertView, ViewGroup parent) {
            // TODO Auto-generated method stub
            GroupViewHolder holder=null;
            if(convertView==null){
                convertView=LayoutInflater.from(context).inflate(groupLayout, null);
                holder=new GroupViewHolder();
                holder.image=(ImageView)convertView.findViewById(groupTo[0]);
                holder.groupName=(TextView)convertView.findViewById(groupTo[1]);
                holder.childCount=(TextView)convertView.findViewById(groupTo[2]);
                convertView.setTag(holder);
            }
            else{
                holder=(GroupViewHolder)convertView.getTag();
            } 
            
            int[] groupIndicator=(int[])groupData.get(groupPosition).get(groupFrom[0]);
            holder.image.setBackgroundResource(groupIndicator[isExpanded?1:0]);
            holder.groupName.setText(groupData.get(groupPosition).get(groupFrom[1]).toString());
            holder.childCount.setText(groupData.get(groupPosition).get(groupFrom[2]).toString());
            
            
            if(groupPosition==groupData.size()-1){
                convertView.setBackgroundResource(R.drawable.list_lastitem_border);
            }
            else{
                convertView.setBackgroundResource(R.drawable.list_item_border);
            }
            //else的情況也要考慮,否則在繪制時出現錯位現象
            
            /**
             * 將剛剛創建的groupItem的相對坐標計算出來放在groupLocation中,這個是初始相對坐標
             * 當點擊打開一級菜單和關閉一級菜單時重新更新每一個group的相對坐標
             */
            
            return convertView;
            /**
             * 不要在適配器中調用適配器的內部方法,不然會出現奇怪的異常
             * 
             */
        }

        @Override
        public boolean hasStableIds() {
            // TODO Auto-generated method stub
            return false;
        }

        @Override
        public boolean isChildSelectable(int groupPosition, int childPosition) {
            // TODO Auto-generated method stub
            return true;
        }

        /**
         * 在設置ExpandableListView的寬度的時候,要注意每次點擊展開或者關閉時,各個Group和所要顯示的Item都會重繪
         * 因此在每次繪制完畢之后都需要對height進行更新
         */
        
        @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 );
            }
        }
        
        
        private int floatToInt(double f){
            if(f>0){
                return (int)(f+0.5);
            }
            else{
                return (int)(f-0.5);
            }
            
        }

    }
    
    /**
     * 這個是ListView的適配器
     * @author DragonGN
     *
     */
    public class MyListViewAdapter extends BaseAdapter{

        Context context=null;
        ArrayList<HashMap<String,Object>> list=null;
        int layout;
        String[] from=null;
        int[] to;
        
        
        
        public MyListViewAdapter(Context context,
                ArrayList<HashMap<String, Object>> list, int layout,
                String[] from, int[] to) {
            super();
            this.context = context;
            this.list = list;
            this.layout = layout;
            this.from = from;
            this.to = to;
        }

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

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

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

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            // TODO Auto-generated method stub
            View listItemView= LayoutInflater.from(context).inflate(layout, null);
            ImageView image=(ImageView)listItemView.findViewById(to[0]);
            TextView text=(TextView)listItemView.findViewById(to[1]);
            image.setImageResource((Integer)list.get(position).get(from[0]));
            text.setText((String)list.get(position).get(from[1]));
            return listItemView;
        }
        
    }

    
        
        
        
    
    

}
View Code


最后附上效果圖:

 頭像重復並不是代碼錯誤,我只是重復添加了幾個聯系人,詳情展開代碼參考。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM