Android开发之ExpandableListView扩展

来源:互联网 发布:js判断app安卓版本号 编辑:程序博客网 时间:2024/05/29 12:05
 

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

分类: Android 3839人阅读 评论(1) 收藏 举报
android扩展layoutobjectstringlistview

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


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

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

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

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

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

[java] view plaincopy
  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] view plaincopy
  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] view plaincopy
  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] view plaincopy
  1. android:clickable="false"  
[html] view plaincopy
  1. android:focusable="false"  
[html] view plaincopy
  1. android:focusableInTouchMode="false"  

 

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

layout/main.xml

[html] view plaincopy
  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] view plaincopy
  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] view plaincopy
  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] view plaincopy
  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] view plaincopy
  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
原创粉丝点击