Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android ExpandableListView相關介紹

Android ExpandableListView相關介紹

編輯:關於Android編程

一、ExpandableListView介紹

    一個垂直滾動的顯示兩個級別(Child,Group)列表項的視圖,列表項來自ExpandableListAdapter 。組可以單獨展開。

  1.重要方法

      expandGroup(int groupPos) :在分組列表視圖中展開一組,

      setSelectedGroup(int groupPosition) :設置選擇指定的組。

      setSelectedChild(int groupPosition, int childPosition, boolean shouldExpandGroup) :設置選擇指定的子項。

      getPackedPositionGroup(long packedPosition) :返回所選擇的組

      getPackedPositionForChild(int groupPosition, int childPosition) :返回所選擇的子項

      getPackedPositionType(long packedPosition) :返回所選擇項的類型(Child,Group)

      isGroupExpanded(int groupPosition) :判斷此組是否展開

 

ExpandableListAdapter

    一個接口,將基礎數據鏈接到一個ExpandableListView。此接口的實施將提供訪問Child的數據(由組分類),並實例化的Child和Group。

  1.重要方法

    getChildId(int groupPosition, int childPosition)獲取與在給定組給予孩子相關的數據。

    getChildrenCount(int groupPosition) 返回在指定Group的Child數目。


2.上代碼

public class MyExpandableListAdapter extends BaseExpandableListAdapter {
    private List groupData;
    private List> childrenData;
    private Context context;

    public MyExpandableListAdapter(Context context, List groupData, List> childrenData) {
        this.context = context;
        this.groupData = groupData;
        this.childrenData = childrenData;
    }

    @Override
    public int getGroupCount() {
        return groupData.size();
    }

    @Override
    public int getChildrenCount(int i) {
        return childrenData.get(i).size();
    }

    @Override
    public Object getGroup(int i) {
        return groupData.get(i);
    }

    @Override
    public Object getChild(int i, int i1) {
        return childrenData.get(i).get(i1);
    }

    @Override
    public long getGroupId(int groupPosition) {
        return groupPosition;
    }

    @Override
    public long getChildId(int groupPosition, int childPosition) {
        return childPosition;
    }

    @Override
    public boolean hasStableIds() {
        return false;
    }

    @Override
    public View getGroupView(int groupPosition, boolean b, View convertView, ViewGroup viewGroup) {
        GroupHolder groupHolder = null;
        if (convertView == null) {
            convertView = View.inflate(context, R.layout.item_head, null);
            groupHolder = new GroupHolder();
            groupHolder.txt = (TextView) convertView.findViewById(R.id.txt);
            convertView.setTag(groupHolder);
        } else {
            groupHolder = (GroupHolder) convertView.getTag();
        }
        groupHolder.txt.setText(groupData.get(groupPosition));
        return convertView;
    }


    @Override
    public View getChildView(int groupPosition, int childPosition,
                             boolean isLastChild, View convertView, ViewGroup parent) {
        ItemHolder itemHolder = null;
        if (convertView == null) {
            convertView = View.inflate(context, R.layout.item_child, null);
            itemHolder = new ItemHolder();
            itemHolder.tv_mes = (TextView) convertView.findViewById(R.id.tv_mes);
            convertView.setTag(itemHolder);
        } else {
            itemHolder = (ItemHolder) convertView.getTag();
        }
        itemHolder.tv_mes.setText(childrenData.get(groupPosition).get(
                childPosition));
        return convertView;
    }

    @Override
    public boolean isChildSelectable(int i, int i1) {
        return true;
    }

    class GroupHolder {
        public TextView txt;
    }

    class ItemHolder {
        public TextView tv_mes;
    }
}
3.MainActivity的代碼
public class MainActivity extends Activity implements  ExpandableListView.OnChildClickListener {

    private List groupArray;
    private List> childArray;
    private ExpandableListView expandableListView;
    private MyExpandableListAdapter mMyExpandableListAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
        initData();
    }

    private void initData() {
        //隨便一堆測試數據
        groupArray = new ArrayList();
        groupArray.add("A");
        groupArray.add("B");
        groupArray.add("C");


        List item_list1 = new ArrayList();
        item_list1.add("1");
        item_list1.add("2");
        item_list1.add("3");

        List item_list2 = new ArrayList();
        item_list2.add("4");
        item_list2.add("5");
        item_list2.add("6");

        List item_list3 = new ArrayList();
        item_list3.add("7");
        item_list3.add("8");
        item_list3.add("9");

        childArray = new ArrayList>();

        childArray.add(item_list1);
        childArray.add(item_list2);
        childArray.add(item_list3);

        mMyExpandableListAdapter = new MyExpandableListAdapter(MainActivity.this, groupArray, childArray);
        expandableListView.setAdapter(mMyExpandableListAdapter);
        for (int i = 0; i < mMyExpandableListAdapter.getGroupCount(); i++) {//展開所有父分組
            expandableListView.expandGroup(i);
        }
    }

    private void initView() {
        expandableListView = (ExpandableListView) findViewById(R.id.expandableListView);
        expandableListView.setOnChildClickListener(this);
    }

    @Override
    public boolean onChildClick(ExpandableListView expandableListView, View view, int groupPosition, int childPosition, long l) {
        Toast.makeText(MainActivity.this, "點擊了" + childArray.get(groupPosition).get(childPosition), Toast.LENGTH_SHORT).show();
        return true;
    }
}
效果如圖
\

4.expandableListview它是如何定義長按事件的呢?

  1. @Override
  2. publicbooleanonItemLongClick(AdapterViewarg0,Viewview,intpos,longid){
  3. //pos不可用說明見下文returnfalse;
  4. }

    如果這個方法是用在ListView長按事件中剛剛好,但在ExpandableListView中,第三個參數pos不能區分開點擊的是父項還是子項,以及哪個父項或子項。

    在ExpandableListView響應的onItemLongCkick方法中,pos參數值為:從上到下,父項+展現的子項到點擊位置的數目(注意:是展現的,隱藏的子項不包括,從0開始)。

    例如:

    父項1(隱藏3個子項)

    父項2

    |—子項2-0

    |—子項2-1

    |—子項2-2

    長按子項2-1時,pos值為3。顯然根據pos值是無法確定點擊的是哪個子項或父項的。

    因此依賴pos是很難處理點擊位置的。

    如果可以直接在onItemLongClick方法中獲取groupPos,及childPos該多好呢?

    下面我就來所說有幾種方法:

    1.這種方法是通過下標來找到位置,

      @Override  
        public boolean onItemLongClick(AdapterView arg0, View view,  
                int pos, long id) {  
          
    
    long packedPosition = mExpandableListView.getExpandableListPosition(i);
    
    int itemType = ExpandableListView.getPackedPositionType(packedPosition);
    int groupPosition = ExpandableListView.getPackedPositionGroup(packedPosition);
    int childPosition = ExpandableListView.getPackedPositionChild(packedPosition);
    
      //根據groupPos判斷你長按的是哪個父項,做相應處理(彈框等)  
            } else {  
                //根據groupPos及childPos判斷你長按的是哪個父項下的哪個子項,然後做相應處理。   
            }  
            return false;  
        }  
    
    
                //根據groupPos判斷你長按的是哪個父項,做相應處理(彈框等)  
            } else {  
                //根據groupPos及childPos判斷你長按的是哪個父項下的哪個子項,然後做相應處理。   
            }  
            return false;  
        }  
    
    PositionMetadata getUnflattenedPos(final int flPos) { /* Keep locally since frequent use */ final ArrayList egml = mExpGroupMetadataList; final int numExpGroups = egml.size(); /* Binary search variables */ int leftExpGroupIndex = 0; int rightExpGroupIndex = numExpGroups - 1; int midExpGroupIndex = 0; GroupMetadata midExpGm; if (numExpGroups == 0) { /* * There aren't any expanded groups (hence no visible children * either), so flPos must be a group and its group pos will be the * same as its flPos */ return PositionMetadata.obtain(flPos, ExpandableListPosition.GROUP, flPos, -1, null, 0); } /* * Binary search over the expanded groups to find either the exact * expanded group (if we're looking for a group) or the group that * contains the child we're looking for. If we are looking for a * collapsed group, we will not have a direct match here, but we will * find the expanded group just before the group we're searching for (so * then we can calculate the group position of the group we're searching * for). If there isn't an expanded group prior to the group being * searched for, then the group being searched for's group position is * the same as the flat list position (since there are no children before * it, and all groups before it are collapsed). */ while (leftExpGroupIndex <= rightExpGroupIndex) { midExpGroupIndex = (rightExpGroupIndex - leftExpGroupIndex) / 2 + leftExpGroupIndex; midExpGm = egml.get(midExpGroupIndex); if (flPos > midExpGm.lastChildFlPos) { /* * The flat list position is after the current middle group's * last child's flat list position, so search right */ leftExpGroupIndex = midExpGroupIndex + 1; } else if (flPos < midExpGm.flPos) { /* * The flat list position is before the current middle group's * flat list position, so search left */ rightExpGroupIndex = midExpGroupIndex - 1; } else if (flPos == midExpGm.flPos) { /* * The flat list position is this middle group's flat list * position, so we've found an exact hit */ return PositionMetadata.obtain(flPos, ExpandableListPosition.GROUP, midExpGm.gPos, -1, midExpGm, midExpGroupIndex); } else if (flPos <= midExpGm.lastChildFlPos /* && flPos > midGm.flPos as deduced from previous * conditions */) { /* The flat list position is a child of the middle group */ /* * Subtract the first child's flat list position from the * specified flat list pos to get the child's position within * the group */ final int childPos = flPos - (midExpGm.flPos + 1); return PositionMetadata.obtain(flPos, ExpandableListPosition.CHILD, midExpGm.gPos, childPos, midExpGm, midExpGroupIndex); } } /* * If we've reached here, it means the flat list position must be a * group that is not expanded, since otherwise we would have hit it * in the above search. */ /** * If we are to expand this group later, where would it go in the * mExpGroupMetadataList ? */ int insertPosition = 0; /** What is its group position in the list of all groups? */ int groupPos = 0; /* * To figure out exact insertion and prior group positions, we need to * determine how we broke out of the binary search. We backtrack * to see this. */ if (leftExpGroupIndex > midExpGroupIndex) { /* * This would occur in the first conditional, so the flat list * insertion position is after the left group. Also, the * leftGroupPos is one more than it should be (since that broke out * of our binary search), so we decrement it. */ final GroupMetadata leftExpGm = egml.get(leftExpGroupIndex-1); insertPosition = leftExpGroupIndex; /* * Sums the number of groups between the prior exp group and this * one, and then adds it to the prior group's group pos */ groupPos = (flPos - leftExpGm.lastChildFlPos) + leftExpGm.gPos; } else if (rightExpGroupIndex < midExpGroupIndex) { /* * This would occur in the second conditional, so the flat list * insertion position is before the right group. Also, the * rightGroupPos is one less than it should be, so increment it. */ final GroupMetadata rightExpGm = egml.get(++rightExpGroupIndex); insertPosition = rightExpGroupIndex; /* * Subtracts this group's flat list pos from the group after's flat * list position to find out how many groups are in between the two * groups. Then, subtracts that number from the group after's group * pos to get this group's pos. */ groupPos = rightExpGm.gPos - (rightExpGm.flPos - flPos); } else { // TODO: clean exit throw new RuntimeException("Unknown state"); } return PositionMetadata.obtain(flPos, ExpandableListPosition.GROUP, groupPos, -1, null, insertPosition); } /** * Translates either a group pos or a child pos (+ group it belongs to) to a * flat list position. If searching for a child and its group is not expanded, this will * return null since the child isn't being shown in the ListView, and hence it has no * position. * * @param pos a {@link ExpandableListPosition} representing either a group position * or child position * @return the flat list position encompassed in a {@link PositionMetadata} * object that contains additional useful info for insertion, etc., or null. */ PositionMetadata getFlattenedPos(final ExpandableListPosition pos) { final ArrayList egml = mExpGroupMetadataList; final int numExpGroups = egml.size(); /* Binary search variables */ int leftExpGroupIndex = 0; int rightExpGroupIndex = numExpGroups - 1; int midExpGroupIndex = 0; GroupMetadata midExpGm; if (numExpGroups == 0) { /* * There aren't any expanded groups, so flPos must be a group and * its flPos will be the same as its group pos. The * insert position is 0 (since the list is empty). */ return PositionMetadata.obtain(pos.groupPos, pos.type, pos.groupPos, pos.childPos, null, 0); } /* * Binary search over the expanded groups to find either the exact * expanded group (if we're looking for a group) or the group that * contains the child we're looking for. */ while (leftExpGroupIndex <= rightExpGroupIndex) { midExpGroupIndex = (rightExpGroupIndex - leftExpGroupIndex)/2 + leftExpGroupIndex; midExpGm = egml.get(midExpGroupIndex); if (pos.groupPos > midExpGm.gPos) { /* * It's after the current middle group, so search right */ leftExpGroupIndex = midExpGroupIndex + 1; } else if (pos.groupPos < midExpGm.gPos) { /* * It's before the current middle group, so search left */ rightExpGroupIndex = midExpGroupIndex - 1; } else if (pos.groupPos == midExpGm.gPos) { /* * It's this middle group, exact hit */ if (pos.type == ExpandableListPosition.GROUP) { /* If it's a group, give them this matched group's flPos */ return PositionMetadata.obtain(midExpGm.flPos, pos.type, pos.groupPos, pos.childPos, midExpGm, midExpGroupIndex); } else if (pos.type == ExpandableListPosition.CHILD) { /* If it's a child, calculate the flat list pos */ return PositionMetadata.obtain(midExpGm.flPos + pos.childPos + 1, pos.type, pos.groupPos, pos.childPos, midExpGm, midExpGroupIndex); } else { return null; } } } /* * If we've reached here, it means there was no match in the expanded * groups, so it must be a collapsed group that they're search for */ if (pos.type != ExpandableListPosition.GROUP) { /* If it isn't a group, return null */ return null; } /* * To figure out exact insertion and prior group positions, we need to * determine how we broke out of the binary search. We backtrack to see * this. */ if (leftExpGroupIndex > midExpGroupIndex) { /* * This would occur in the first conditional, so the flat list * insertion position is after the left group. * * The leftGroupPos is one more than it should be (from the binary * search loop) so we subtract 1 to get the actual left group. Since * the insertion point is AFTER the left group, we keep this +1 * value as the insertion point */ final GroupMetadata leftExpGm = egml.get(leftExpGroupIndex-1); final int flPos = leftExpGm.lastChildFlPos + (pos.groupPos - leftExpGm.gPos); return PositionMetadata.obtain(flPos, pos.type, pos.groupPos, pos.childPos, null, leftExpGroupIndex); } else if (rightExpGroupIndex < midExpGroupIndex) { /* * This would occur in the second conditional, so the flat list * insertion position is before the right group. Also, the * rightGroupPos is one less than it should be (from binary search * loop), so we increment to it. */ final GroupMetadata rightExpGm = egml.get(++rightExpGroupIndex); final int flPos = rightExpGm.flPos - (rightExpGm.gPos - pos.groupPos); return PositionMetadata.obtain(flPos, pos.type, pos.groupPos, pos.childPos, null, rightExpGroupIndex); } else { return null; } } 

    
    基本就是我們高中學的數學那套,找規律,判斷點擊的child是在第幾組,在判斷是第幾個。2.這種方法我看了一下,和第一種方法差不多,這種是通過id來判斷位置
    
    getExpandableListView().setOnItemLongClickListener(new OnItemLongClickListener() {
        @Override
        public boolean onItemLongClick(AdapterView parent, View view, int position, long id) {
            if (ExpandableListView.getPackedPositionType(id) == ExpandableListView.PACKED_POSITION_TYPE_CHILD) {
                int groupPosition = ExpandableListView.getPackedPositionGroup(id);
                int childPosition = ExpandableListView.getPackedPositionChild(id);
    
                // You now have everything that you would as if this was an OnChildClickListener() 
                // Add your logic here.
    
                // Return true as we are handling the event.
                return true;
            }
    
            return false;
        }
    });

    3,(這是網上搜的,你說寫就寫呗,還不讓人看明白了,自己被坑了)

    使用上下文菜單實現長按事件
    
    注冊上下文菜單 registerForContextMenu(downElv);,並重新下面兩個方法:
    
    @Override
    public void onCreateContextMenu(ContextMenu menu, View v,
    ContextMenuInfo menuInfo) {
    super.onCreateContextMenu(menu, v, menuInfo);
    ExpandableListView.ExpandableListContextMenuInfo info = (ExpandableListView.ExpandableListContextMenuInfo) menuInfo;
    //menuinfo該對象提供了選中對象的附加信息
    
    int type = ExpandableListView
    .getPackedPositionType(info.packedPosition);
    
    int group = ExpandableListView
    .getPackedPositionGroup(info.packedPosition);
    
    int child = ExpandableListView
    .getPackedPositionChild(info.packedPosition);
    
    System.out.println("LongClickListener*type-------------------------"
    + type);
    System.out.println("LongClickListener*group-------------------------"
    + group);
    System.out.println("LongClickListener*child-------------------------"
    + child);
    this.setMGroupID(group);
    this.setMChildrenID(child);
    //處理邏輯
    if (type == 0) {// 分組長按事件
    showDialog(Globals.DIALOG_GROUPS_LONGCLICK);
    } else if (type == 1) {// 長按好友列表項
       //showDialog(Globals.DIALOG_FRIENDlIST_LONGCLICK);可以自定義Dialog顯示,
    
    也可以使用menu.add(0,0,0,"增加");添加菜單項
    }
    
    }
    
    //一般在此函數下面編寫響應事件
    @Override
    public boolean onContextItemSelected(MenuItem item) {
    return super.onContextItemSelected(item);
    }
    
    

    4,(這也是網上說的最多的,自己也被坑了,不知道view是復用的啊)看到了onItemLongClick方法第二個參數:view。這裡的view是你按中的位置對應的view。view有個方法getTag(int key)。如果在創建此view的時候就把groupPos,childPos通過setTag(int key, Object value)設置進去,在響應onItemLongClick不就可以直接拿出來用了麼。

    現在就要講到必須使用自定義的BaseExpandableListAdapter的理由了。

    要把groupPos,childPos通過setTag的方式綁定到view中,就必須操作該view的創建過程。要控制這個過程就必須要在自定義BaseExpandableListAdapter中重寫getGroupView及getChildView方法進行操作。如下:

      @Override  
        public View getChildView(int groupPosition, int childPosition,  
                boolean isLastChild, View convertView, ViewGroup parent) {  
            //我這裡僅通過自己寫的mkChildView()方法創建TextView來顯示文字,更復雜的可以通過LayoutInflater來填充一個view  
            TextView childTv = mkChildView();  
            // 標記位置  
            // 必須使用資源Id當key(不是資源id會出現運行時異常),android本意應該是想用tag來保存資源id對應組件。  
            // 將groupPosition,childPosition通過setTag保存,在onItemLongClick方法中就可以通過view參數直接拿到了!  
                    childTv.setTag(R.id.xxx01, groupPosition);  
            childTv.setTag(R.id.xxx02, childPosition);  
            return childTv;  
        }  
      
        @Override  
        public View getGroupView(int groupPosition, boolean isExpanded,  
                View convertView, ViewGroup parent) {  
            TextView groupTv = mkGroupView();  
            // 設置同getChildView一樣  
            groupTv.setTag(R.id.xxx01, groupPosition);  
            groupTv.setTag(R.id.xxx02, -1); //設置-1表示長按時點擊的是父項,到時好判斷。  
            groupTv.setText(groups[groupPosition]);  
            return groupTv;  
        }  
    }  
    通過這個expandablelistview,自己看到了自己很多不足,自己要多努力了。






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