关闭

Android开发之ExpandableListView扩展(BaseExpandableListAdapter的使用)(完整版)

1048人阅读 评论(0) 收藏 举报

上一篇文章中谈到之前的代码中有一个问题。http://blog.csdn.net/benw1988/article/details/6871244


程序本身还存在问题,checkbox在点击修改了状态之后,缩小组,在展开组,checkbox的状态会还原。

这是因为,在点击展开时,会重新调用getChildView函数,于是子列表的中的数据重新初始化了。所以数据就还原了。

因此,这个位置的代码还需要修改。才能满足要求。

这一次修改之后,解决了这个问题,当然对源代码进行了一些修改。

在ExpandableListActivity中的onChildClick事件中进行了部分操作。

Java代码 复制代码
  1. CheckBox c = (CheckBox) v.getTag();   
  2. c.toggle();   
  3. adapter.updateChildData(groupPosition, childPosition);   
  4. return super.onChildClick(parent, v, groupPosition, childPosition, id);  

首先得到在Adapter中标记的Checkbox。(View中的setTag(Onbect)表示给View添加一个格外的数据,以后可以用getTag()将这个数据取出来。)

然后设置Checkbox点击。

然后再修改adapter中的ChildData也就是子列表里数据。所以,相应的在Adapter中也进行了修改:

Java代码 复制代码
  1. private void bindChildView(View view, Map<String, ?> data, String[] from,   
  2.             int[] to) {   
  3.         TextView v = (TextView) view.findViewById(to[0]);   
  4.         if (v != null) {   
  5.             v.setText((String) data.get(from[0]));   
  6.         }   
  7.         CheckBox c = (CheckBox) view.findViewById(to[1]);   
  8.         // View中的setTag(Onbect)表示给View添加一个格外的数据,以后可以用getTag()将这个数据取出来。   
  9.         view.setTag(c);   
  10.         if (c != null) {   
  11.             if (data.get(from[1]).equals(0)) {   
  12.                 c.setChecked(true);   
  13.             } else {   
  14.                 c.setChecked(false);   
  15.             }   
  16.         }   
  17.     }  

updateChildData函数如下:

Java代码 复制代码
  1. public void updateChildData(int groupPosition, int childPosition) {   
  2.         int checked = (Integer) mChildData.get(groupPosition)   
  3.                 .get(childPosition).get("childCheckBox");   
  4.         mChildData.get(groupPosition).get(childPosition)   
  5.                 .remove("childCheckBox");   
  6.         if (checked == 0) {   
  7.             mChildData.get(groupPosition).get(childPosition)   
  8.                     .put("childCheckBox"1);   
  9.         } else if (checked == 1) {   
  10.             mChildData.get(groupPosition).get(childPosition)   
  11.                     .put("childCheckBox"0);   
  12.         }   
  13.     }  

因为使用的是Map,不能直接修改里面的数据,所以先获取Map中childCheckBox里面的值

然后删除这个映射,根据原来的这个值,重新添加一个新的映射进去。

为了可以让Activity中的onChildClick事件得到响应,我们需要将Checkbox的焦点去掉。

在childs.xml的CheckBox中加入三个属性:

Html代码 复制代码
  1. android:clickable="false"  
Html代码 复制代码
  1. android:focusable="false"  
Html代码 复制代码
  1. android:focusableInTouchMode="false"  

这样之后,就可以解决上面说的那个问题。

layout/main.xml

Html代码 复制代码
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:orientation="vertical"    
  4.     android:layout_width="fill_parent"  
  5.     android:layout_height="fill_parent">  
  6.     <ExpandableListView    
  7.         android:id="@id/android:list"  
  8.         android:layout_width="fill_parent"    
  9.         android:layout_height="fill_parent">  
  10.     </ExpandableListView>  
  11.     <TextView    
  12.         android:layout_width="fill_parent"  
  13.         android:layout_height="fill_parent"    
  14.         android:id="@id/android:empty"  
  15.         android:text="No Data" />  
  16. </LinearLayout>  

layout/groups.xml

Html代码 复制代码
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:orientation="vertical"    
  4.     android:layout_width="match_parent"  
  5.     android:layout_height="match_parent">  
  6.     <TextView    
  7.         android:id="@+id/groupTextView"  
  8.         android:layout_width="fill_parent"  
  9.         android:layout_height="fill_parent"    
  10.         android:textSize="25sp"    
  11.         android:paddingLeft="35px"    
  12.         android:paddingTop="10px"  
  13.         android:paddingRight="5px"    
  14.         android:paddingBottom="10px"    
  15.         android:text="No Data" />  
  16. </LinearLayout>  


layout/childs.xml

Html代码 复制代码
  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.     <TextView    
  6.         android:id="@+id/childTextView"  
  7.         android:layout_width="wrap_content"  
  8.         android:layout_height="match_parent"  
  9.         android:layout_alignParentLeft="true"  
  10.         android:textSize="22sp"  
  11.         android:layout_marginLeft="30dip"  
  12.         android:layout_marginTop="5dip"  
  13.         android:text="No Data" />  
  14.     <CheckBox    
  15.         android:id="@+id/childCheckBox"  
  16.         android:layout_width="wrap_content"  
  17.         android:layout_height="match_parent"  
  18.         android:layout_alignParentRight="true"  
  19.         android:layout_marginLeft="50dip"  
  20.         android:clickable="false"  
  21.         android:focusable="false"  
  22.         android:focusableInTouchMode="false"/>  
  23. </RelativeLayout>  


主类:ExpandableListViewActivity.java

Java代码 复制代码
  1. package com.zeph.android.expandablelistview.example;   
  2.   
  3. import java.util.ArrayList;   
  4. import java.util.HashMap;   
  5. import java.util.List;   
  6. import java.util.Map;   
  7.   
  8. import android.app.ExpandableListActivity;   
  9. import android.os.Bundle;   
  10. import android.view.View;   
  11. import android.widget.CheckBox;   
  12. import android.widget.ExpandableListView;   
  13.   
  14. public class ExpandableListViewActivity extends ExpandableListActivity {   
  15.     private MyExpandableListViewAdapter adapter;   
  16.   
  17.     @Override  
  18.     public void onCreate(Bundle savedInstanceState) {   
  19.         super.onCreate(savedInstanceState);   
  20.         setContentView(R.layout.main);   
  21.   
  22.         // 创建两个一级条目标题   
  23.         List<Map<String, String>> groupData = new ArrayList<Map<String, String>>();   
  24.         Map<String, String> groupData1 = new HashMap<String, String>();   
  25.         groupData1.put("groupTextView""新闻");// group对应layout中的id:group   
  26.         Map<String, String> groupData2 = new HashMap<String, String>();   
  27.         groupData2.put("groupTextView""科技");   
  28.         groupData.add(groupData1);   
  29.         groupData.add(groupData2);   
  30.   
  31.         // 创建第一个一级条目下的的二级条目   
  32.         List<Map<String, Object>> child1 = new ArrayList<Map<String, Object>>();   
  33.         Map<String, Object> childData1 = new HashMap<String, Object>();   
  34.   
  35.         childData1.put("childTextView""网易头条新闻");// 同理   
  36.         childData1.put("childCheckBox"0);// 同理   
  37.         Map<String, Object> childData2 = new HashMap<String, Object>();   
  38.         childData2.put("childTextView""凤凰网新闻");   
  39.         childData2.put("childCheckBox"0);   
  40.         child1.add(childData1);   
  41.         child1.add(childData2);   
  42.   
  43.         // 创建第二个一级条目下的的二级条目   
  44.         List<Map<String, Object>> child2 = new ArrayList<Map<String, Object>>();   
  45.         Map<String, Object> childData3 = new HashMap<String, Object>();   
  46.   
  47.         childData3.put("childTextView""TechWeb");   
  48.         childData3.put("childCheckBox"1);   
  49.         Map<String, Object> childData4 = new HashMap<String, Object>();   
  50.         childData4.put("childTextView""月光博客");   
  51.         childData4.put("childCheckBox"1);   
  52.         child2.add(childData3);   
  53.         child2.add(childData4);   
  54.   
  55.         // 将二级条目放在一个集合里,供显示时使用   
  56.         List<List<Map<String, Object>>> childData = new ArrayList<List<Map<String, Object>>>();   
  57.         childData.add(child1);   
  58.         childData.add(child2);   
  59.         adapter = new MyExpandableListViewAdapter(getApplicationContext(),   
  60.                 groupData, R.layout.groups, new String[] { "groupTextView" },   
  61.                 new int[] { R.id.groupTextView }, childData, R.layout.childs,   
  62.                 new String[] { "childTextView""childCheckBox" }, new int[] {   
  63.                         R.id.childTextView, R.id.childCheckBox });   
  64.         setListAdapter(adapter);   
  65.     }   
  66.   
  67.     /**  
  68.      * 设置哪个二级目录被默认选中  
  69.      */  
  70.     @Override  
  71.     public boolean setSelectedChild(int groupPosition, int childPosition,   
  72.             boolean shouldExpandGroup) {   
  73.         // do something   
  74.         return super.setSelectedChild(groupPosition, childPosition,   
  75.                 shouldExpandGroup);   
  76.     }   
  77.   
  78.     /**  
  79.      * 设置哪个一级目录被默认选中  
  80.      */  
  81.     @Override  
  82.     public void setSelectedGroup(int groupPosition) {   
  83.         // do something   
  84.         super.setSelectedGroup(groupPosition);   
  85.     }   
  86.   
  87.     /**  
  88.      * 当二级条目被点击时响应  
  89.      */  
  90.     @Override  
  91.     public boolean onChildClick(ExpandableListView parent, View v,   
  92.             int groupPosition, int childPosition, long id) {   
  93.         CheckBox c = (CheckBox) v.getTag();   
  94.         c.toggle();   
  95.         adapter.updateChildData(groupPosition, childPosition);   
  96.         return super.onChildClick(parent, v, groupPosition, childPosition, id);   
  97.     }   
  98. }  

Adapter:MyExpandableListViewAdapter.java

Java代码 复制代码
  1. package com.zeph.android.expandablelistview.example;   
  2.   
  3. import java.util.List;   
  4. import java.util.Map;   
  5.   
  6. import android.content.Context;   
  7. import android.view.LayoutInflater;   
  8. import android.view.View;   
  9. import android.view.ViewGroup;   
  10. import android.widget.BaseExpandableListAdapter;   
  11. import android.widget.CheckBox;   
  12. import android.widget.TextView;   
  13.   
  14. /**  
  15.  * 首个List对应子元素中所代表的组,第二个List对应孙子元素在子元素组中的位置. Map亦将支持这样的特殊元素。(子元素嵌套组元素的情况)  
  16.  * 将XML文件中定义的静态数据映射到组及其视图的简单的适配器. 你可以用 Map的列表,为组指定其后台数据。每个数组元素对应一个可展开列表的一个组。  
  17.  * Maps 包含每行的数据。你还可以指定 XML 文件来定义用于显示组的视图, 并通过 Map 的键值映射到指定的视图。该过程适用于组的子元素。  
  18.  * 单级以外的可展开列表的后台数据类型为List<List<Map>>,  
  19.  * 第一级列表对应可扩展视图组中的组视图,第二级列表对应组的子组视图, 最后 Map 保持子组视图的子视图的数据。  
  20.  *   
  21.  * @author BenZeph (以下代码和注释均参考了工具屋,网址:http://code.google.com/p/toolib/)  
  22.  */  
  23. public class MyExpandableListViewAdapter extends BaseExpandableListAdapter {   
  24.   
  25.     private List<? extends Map<String, ?>> mGroupData;   
  26.     private int mExpandedGroupLayout;   
  27.     private int mCollapsedGroupLayout;   
  28.     private String[] mGroupFrom;   
  29.     private int[] mGroupTo;   
  30.   
  31.     private List<? extends List<? extends Map<String, Object>>> mChildData;   
  32.     private int mChildLayout;   
  33.     private int mLastChildLayout;   
  34.     private String[] mChildFrom;   
  35.     private int[] mChildTo;   
  36.   
  37.     private LayoutInflater mInflater;   
  38.   
  39.     /**  
  40.      * 调用另外一个构造函数,其中From和To的含义和不同的ListView相同,  
  41.      * 可以参考ListView或者SimpleExpandableListViewAdapter  
  42.      *   
  43.      * @param context  
  44.      * @param groupData  
  45.      * @param groupLayout  
  46.      * @param groupFrom  
  47.      * @param groupTo  
  48.      * @param childData  
  49.      * @param childLayout  
  50.      * @param childFrom  
  51.      * @param childTo  
  52.      */  
  53.     public MyExpandableListViewAdapter(Context context,   
  54.             List<? extends Map<String, ?>> groupData, int groupLayout,   
  55.             String[] groupFrom, int[] groupTo,   
  56.             List<? extends List<? extends Map<String, Object>>> childData,   
  57.             int childLayout, String[] childFrom, int[] childTo) {   
  58.         this(context, groupData, groupLayout, groupLayout, groupFrom, groupTo,   
  59.                 childData, childLayout, childLayout, childFrom, childTo);   
  60.     }   
  61.   
  62.     /**  
  63.      *   
  64.      * @param context  
  65.      * @param groupData  
  66.      * @param expandedGroupLayout  
  67.      * @param collapsedGroupLayout  
  68.      * @param groupFrom  
  69.      * @param groupTo  
  70.      * @param childData  
  71.      * @param childLayout  
  72.      * @param lastChildLayout  
  73.      * @param childFrom  
  74.      * @param childTo  
  75.      */  
  76.     public MyExpandableListViewAdapter(Context context,   
  77.             List<? extends Map<String, ?>> groupData, int expandedGroupLayout,   
  78.             int collapsedGroupLayout, String[] groupFrom, int[] groupTo,   
  79.             List<? extends List<? extends Map<String, Object>>> childData,   
  80.             int childLayout, int lastChildLayout, String[] childFrom,   
  81.             int[] childTo) {   
  82.         mGroupData = groupData;   
  83.         mExpandedGroupLayout = expandedGroupLayout;   
  84.         mCollapsedGroupLayout = collapsedGroupLayout;   
  85.         mGroupFrom = groupFrom;   
  86.         mGroupTo = groupTo;   
  87.         mChildData = childData;   
  88.         mChildLayout = childLayout;   
  89.         mLastChildLayout = lastChildLayout;   
  90.         mChildFrom = childFrom;   
  91.         mChildTo = childTo;   
  92.         mInflater = (LayoutInflater) context   
  93.                 .getSystemService(Context.LAYOUT_INFLATER_SERVICE);   
  94.     }   
  95.   
  96.     @Override  
  97.     public Object getChild(int groupPosition, int childPosition) {   
  98.         // 取得与指定分组、指定子项目关联的数据。   
  99.         return mChildData.get(groupPosition).get(childPosition);   
  100.     }   
  101.   
  102.     @Override  
  103.     public long getChildId(int groupPosition, int childPosition) {   
  104.         // 取得给定分组中给定子视图的ID。 该组ID必须在组中是唯一的。组合的ID (参见getCombinedGroupId(long))   
  105.         // 必须不同于其他所有ID(分组及子项目的ID)。   
  106.         return childPosition;   
  107.     }   
  108.   
  109.     @Override  
  110.     public View getChildView(int groupPosition, int childPosition,   
  111.             boolean isLastChild, View convertView, ViewGroup parent) {   
  112.         // 取得显示给定分组给定子位置的数据用的视图。   
  113.         View v;   
  114.         if (convertView == null) {   
  115.             v = newChildView(isLastChild, parent);   
  116.         } else {   
  117.             v = convertView;   
  118.         }   
  119.         bindChildView(v, mChildData.get(groupPosition).get(childPosition),   
  120.                 mChildFrom, mChildTo);   
  121.         return v;   
  122.     }   
  123.   
  124.     @Override  
  125.     public int getChildrenCount(int groupPosition) {   
  126.         // 取得指定分组的子元素数。   
  127.         return mChildData.get(groupPosition).size();   
  128.     }   
  129.   
  130.     @Override  
  131.     public Object getGroup(int groupPosition) {   
  132.         // 取得与给定分组关联的数据。   
  133.         return mGroupData.get(groupPosition);   
  134.     }   
  135.   
  136.     @Override  
  137.     public int getGroupCount() {   
  138.         // 取得分组数   
  139.         return mChildData.size();   
  140.     }   
  141.   
  142.     @Override  
  143.     public long getGroupId(int groupPosition) {   
  144.         // 取得指定分组的ID。该组ID必须在组中是唯一的。组合的ID (参见getCombinedGroupId(long))   
  145.         // 必须不同于其他所有ID(分组及子项目的ID)。   
  146.         return groupPosition;   
  147.     }   
  148.   
  149.     @Override  
  150.     public View getGroupView(int groupPosition, boolean isExpanded,   
  151.             View convertView, ViewGroup parent) {   
  152.         // 取得用于显示给定分组的视图。 这个方法仅返回分组的视图对象, 要想获取子元素的视图对象,   
  153.         // 就需要调用 getChildView(int, int, boolean, View, ViewGroup)。   
  154.         View v;   
  155.         if (convertView == null) {   
  156.             v = newGroupView(isExpanded, parent);   
  157.         } else {   
  158.             v = convertView;   
  159.         }   
  160.         bindGroupView(v, mGroupData.get(groupPosition), mGroupFrom, mGroupTo);   
  161.         return v;   
  162.     }   
  163.   
  164.     @Override  
  165.     public boolean hasStableIds() {   
  166.         // 是否指定分组视图及其子视图的ID对应的后台数据改变也会保持该ID。   
  167.         return true;   
  168.     }   
  169.   
  170.     @Override  
  171.     public boolean isChildSelectable(int groupPosition, int childPosition) {   
  172.         // 指定位置的子视图是否可选择。   
  173.         return true;   
  174.     }   
  175.   
  176.     /**  
  177.      * 创建新的组视图  
  178.      *   
  179.      * @param isExpanded  
  180.      * @param parent  
  181.      * @return  
  182.      */  
  183.     public View newGroupView(boolean isExpanded, ViewGroup parent) {   
  184.         return mInflater.inflate((isExpanded) ? mExpandedGroupLayout   
  185.                 : mCollapsedGroupLayout, parent, false);   
  186.     }   
  187.   
  188.     /**  
  189.      * 创建新的子视图  
  190.      *   
  191.      * @param isLastChild  
  192.      * @param parent  
  193.      * @return  
  194.      */  
  195.     public View newChildView(boolean isLastChild, ViewGroup parent) {   
  196.         return mInflater.inflate((isLastChild) ? mLastChildLayout   
  197.                 : mChildLayout, parent, false);   
  198.     }   
  199.   
  200.     /**  
  201.      * 绑定组数据  
  202.      *   
  203.      * @param view  
  204.      * @param data  
  205.      * @param from  
  206.      * @param to  
  207.      */  
  208.     private void bindGroupView(View view, Map<String, ?> data, String[] from,   
  209.             int[] to) {   
  210.         // 绑定组视图的数据,针对Group的Layout都是TextView的情况   
  211.         int len = to.length;   
  212.         for (int i = 0; i < len; i++) {   
  213.             TextView v = (TextView) view.findViewById(to[i]);   
  214.             if (v != null) {   
  215.                 v.setText((String) data.get(from[i]));   
  216.             }   
  217.         }   
  218.     }   
  219.   
  220.     /**  
  221.      * 绑定子数据  
  222.      *   
  223.      * @param view  
  224.      * @param data  
  225.      * @param from  
  226.      * @param to  
  227.      */  
  228.     private void bindChildView(View view, Map<String, ?> data, String[] from,   
  229.             int[] to) {   
  230.         TextView v = (TextView) view.findViewById(to[0]);   
  231.         if (v != null) {   
  232.             v.setText((String) data.get(from[0]));   
  233.         }   
  234.         CheckBox c = (CheckBox) view.findViewById(to[1]);   
  235.         // View中的setTag(Onbect)表示给View添加一个格外的数据,以后可以用getTag()将这个数据取出来。   
  236.         view.setTag(c);   
  237.         if (c != null) {   
  238.             if (data.get(from[1]).equals(0)) {   
  239.                 c.setChecked(true);   
  240.             } else {   
  241.                 c.setChecked(false);   
  242.             }   
  243.         }   
  244.     }   
  245.   
  246.     public void updateChildData(int groupPosition, int childPosition) {   
  247.         int checked = (Integer) mChildData.get(groupPosition)   
  248.                 .get(childPosition).get("childCheckBox");   
  249.         mChildData.get(groupPosition).get(childPosition)   
  250.                 .remove("childCheckBox");   
  251.         if (checked == 0) {   
  252.             mChildData.get(groupPosition).get(childPosition)   
  253.                     .put("childCheckBox"1);   
  254.         } else if (checked == 1) {   
  255.             mChildData.get(groupPosition).get(childPosition)   
  256.                     .put("childCheckBox"0);   
  257.         }   
  258.     }   
  259. }  


这里就不上图了。效果是一样的。

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:354443次
    • 积分:4001
    • 等级:
    • 排名:第8092名
    • 原创:40篇
    • 转载:269篇
    • 译文:0篇
    • 评论:38条
    最新评论