`

androiddd

 
阅读更多
S & Android DevCamp社区会员特惠限时抢票!                    CSDN账号全站整合公告                 不用买彩票,就有408万!
Android开发之ExpandableListView扩展(BaseExpandableListAdapter的使用)(完整版)
分类: Android 2011-10-14 00:38 694人阅读 评论(0) 收藏 举报

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


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

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

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

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

在ExpandableListActivity中的onChildClick事件中进行了部分操作。
[java] view plaincopy

    CheckBox c = (CheckBox) v.getTag(); 
    c.toggle(); 
    adapter.updateChildData(groupPosition, childPosition); 
    return super.onChildClick(parent, v, groupPosition, childPosition, id); 

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

然后设置Checkbox点击。

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

    private void bindChildView(View view, Map<String, ?> data, String[] from, 
                int[] to) { 
            TextView v = (TextView) view.findViewById(to[0]); 
            if (v != null) { 
                v.setText((String) data.get(from[0])); 
            } 
            CheckBox c = (CheckBox) view.findViewById(to[1]); 
            // View中的setTag(Onbect)表示给View添加一个格外的数据,以后可以用getTag()将这个数据取出来。 
            view.setTag(c); 
            if (c != null) { 
                if (data.get(from[1]).equals(0)) { 
                    c.setChecked(true); 
                } else { 
                    c.setChecked(false); 
                } 
            } 
        } 

updateChildData函数如下:
[java] view plaincopy

    public void updateChildData(int groupPosition, int childPosition) { 
            int checked = (Integer) mChildData.get(groupPosition) 
                    .get(childPosition).get("childCheckBox"); 
            mChildData.get(groupPosition).get(childPosition) 
                    .remove("childCheckBox"); 
            if (checked == 0) { 
                mChildData.get(groupPosition).get(childPosition) 
                        .put("childCheckBox", 1); 
            } else if (checked == 1) { 
                mChildData.get(groupPosition).get(childPosition) 
                        .put("childCheckBox", 0); 
            } 
        } 

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

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

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

在childs.xml的CheckBox中加入三个属性:
[html] view plaincopy

    android:clickable="false" 

[html] view plaincopy

    android:focusable="false" 

[html] view plaincopy

    android:focusableInTouchMode="false" 



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

layout/main.xml
[html] view plaincopy

    <?xml version="1.0" encoding="utf-8"?> 
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
        android:orientation="vertical"  
        android:layout_width="fill_parent" 
        android:layout_height="fill_parent"> 
        <ExpandableListView  
            android:id="@id/android:list" 
            android:layout_width="fill_parent"  
            android:layout_height="fill_parent"> 
        </ExpandableListView> 
        <TextView  
            android:layout_width="fill_parent" 
            android:layout_height="fill_parent"  
            android:id="@id/android:empty" 
            android:text="No Data" /> 
    </LinearLayout> 

layout/groups.xml
[html] view plaincopy

    <?xml version="1.0" encoding="utf-8"?> 
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
        android:orientation="vertical"  
        android:layout_width="match_parent" 
        android:layout_height="match_parent"> 
        <TextView  
            android:id="@+id/groupTextView" 
            android:layout_width="fill_parent" 
            android:layout_height="fill_parent"  
            android:textSize="25sp"  
            android:paddingLeft="35px"  
            android:paddingTop="10px" 
            android:paddingRight="5px"  
            android:paddingBottom="10px"  
            android:text="No Data" /> 
    </LinearLayout> 


layout/childs.xml
[html] view plaincopy

    <?xml version="1.0" encoding="utf-8"?> 
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
        android:layout_width="match_parent" 
        android:layout_height="match_parent"> 
        <TextView  
            android:id="@+id/childTextView" 
            android:layout_width="wrap_content" 
            android:layout_height="match_parent" 
            android:layout_alignParentLeft="true" 
            android:textSize="22sp" 
            android:layout_marginLeft="30dip" 
            android:layout_marginTop="5dip" 
            android:text="No Data" /> 
        <CheckBox  
            android:id="@+id/childCheckBox" 
            android:layout_width="wrap_content" 
            android:layout_height="match_parent" 
            android:layout_alignParentRight="true" 
            android:layout_marginLeft="50dip" 
            android:clickable="false" 
            android:focusable="false" 
            android:focusableInTouchMode="false"/> 
    </RelativeLayout> 


主类:ExpandableListViewActivity.java
[java] view plaincopy

    package com.zeph.android.expandablelistview.example; 
     
    import java.util.ArrayList; 
    import java.util.HashMap; 
    import java.util.List; 
    import java.util.Map; 
     
    import android.app.ExpandableListActivity; 
    import android.os.Bundle; 
    import android.view.View; 
    import android.widget.CheckBox; 
    import android.widget.ExpandableListView; 
     
    public class ExpandableListViewActivity extends ExpandableListActivity { 
        private MyExpandableListViewAdapter adapter; 
     
        @Override 
        public void onCreate(Bundle savedInstanceState) { 
            super.onCreate(savedInstanceState); 
            setContentView(R.layout.main); 
     
            // 创建两个一级条目标题 
            List<Map<String, String>> groupData = new ArrayList<Map<String, String>>(); 
            Map<String, String> groupData1 = new HashMap<String, String>(); 
            groupData1.put("groupTextView", "新闻");// group对应layout中的id:group 
            Map<String, String> groupData2 = new HashMap<String, String>(); 
            groupData2.put("groupTextView", "科技"); 
            groupData.add(groupData1); 
            groupData.add(groupData2); 
     
            // 创建第一个一级条目下的的二级条目 
            List<Map<String, Object>> child1 = new ArrayList<Map<String, Object>>(); 
            Map<String, Object> childData1 = new HashMap<String, Object>(); 
     
            childData1.put("childTextView", "网易头条新闻");// 同理 
            childData1.put("childCheckBox", 0);// 同理 
            Map<String, Object> childData2 = new HashMap<String, Object>(); 
            childData2.put("childTextView", "凤凰网新闻"); 
            childData2.put("childCheckBox", 0); 
            child1.add(childData1); 
            child1.add(childData2); 
     
            // 创建第二个一级条目下的的二级条目 
            List<Map<String, Object>> child2 = new ArrayList<Map<String, Object>>(); 
            Map<String, Object> childData3 = new HashMap<String, Object>(); 
     
            childData3.put("childTextView", "TechWeb"); 
            childData3.put("childCheckBox", 1); 
            Map<String, Object> childData4 = new HashMap<String, Object>(); 
            childData4.put("childTextView", "月光博客"); 
            childData4.put("childCheckBox", 1); 
            child2.add(childData3); 
            child2.add(childData4); 
     
            // 将二级条目放在一个集合里,供显示时使用 
            List<List<Map<String, Object>>> childData = new ArrayList<List<Map<String, Object>>>(); 
            childData.add(child1); 
            childData.add(child2); 
            adapter = new MyExpandableListViewAdapter(getApplicationContext(), 
                    groupData, R.layout.groups, new String[] { "groupTextView" }, 
                    new int[] { R.id.groupTextView }, childData, R.layout.childs, 
                    new String[] { "childTextView", "childCheckBox" }, new int[] { 
                            R.id.childTextView, R.id.childCheckBox }); 
            setListAdapter(adapter); 
        } 
     
        /**
         * 设置哪个二级目录被默认选中
         */ 
        @Override 
        public boolean setSelectedChild(int groupPosition, int childPosition, 
                boolean shouldExpandGroup) { 
            // do something 
            return super.setSelectedChild(groupPosition, childPosition, 
                    shouldExpandGroup); 
        } 
     
        /**
         * 设置哪个一级目录被默认选中
         */ 
        @Override 
        public void setSelectedGroup(int groupPosition) { 
            // do something 
            super.setSelectedGroup(groupPosition); 
        } 
     
        /**
         * 当二级条目被点击时响应
         */ 
        @Override 
        public boolean onChildClick(ExpandableListView parent, View v, 
                int groupPosition, int childPosition, long id) { 
            CheckBox c = (CheckBox) v.getTag(); 
            c.toggle(); 
            adapter.updateChildData(groupPosition, childPosition); 
            return super.onChildClick(parent, v, groupPosition, childPosition, id); 
        } 
    } 



Adapter:MyExpandableListViewAdapter.java
[java] view plaincopy

    package com.zeph.android.expandablelistview.example; 
     
    import java.util.List; 
    import java.util.Map; 
     
    import android.content.Context; 
    import android.view.LayoutInflater; 
    import android.view.View; 
    import android.view.ViewGroup; 
    import android.widget.BaseExpandableListAdapter; 
    import android.widget.CheckBox; 
    import android.widget.TextView; 
     
    /**
     * 首个List对应子元素中所代表的组,第二个List对应孙子元素在子元素组中的位置. Map亦将支持这样的特殊元素。(子元素嵌套组元素的情况)
     * 将XML文件中定义的静态数据映射到组及其视图的简单的适配器. 你可以用 Map的列表,为组指定其后台数据。每个数组元素对应一个可展开列表的一个组。
     * Maps 包含每行的数据。你还可以指定 XML 文件来定义用于显示组的视图, 并通过 Map 的键值映射到指定的视图。该过程适用于组的子元素。
     * 单级以外的可展开列表的后台数据类型为List<List<Map>>,
     * 第一级列表对应可扩展视图组中的组视图,第二级列表对应组的子组视图, 最后 Map 保持子组视图的子视图的数据。
     * 
     * @author BenZeph (以下代码和注释均参考了工具屋,网址:http://code.google.com/p/toolib/)
     */ 
    public class MyExpandableListViewAdapter extends BaseExpandableListAdapter { 
     
        private List<? extends Map<String, ?>> mGroupData; 
        private int mExpandedGroupLayout; 
        private int mCollapsedGroupLayout; 
        private String[] mGroupFrom; 
        private int[] mGroupTo; 
     
        private List<? extends List<? extends Map<String, Object>>> mChildData; 
        private int mChildLayout; 
        private int mLastChildLayout; 
        private String[] mChildFrom; 
        private int[] mChildTo; 
     
        private LayoutInflater mInflater; 
     
        /**
         * 调用另外一个构造函数,其中From和To的含义和不同的ListView相同,
         * 可以参考ListView或者SimpleExpandableListViewAdapter
         * 
         * @param context
         * @param groupData
         * @param groupLayout
         * @param groupFrom
         * @param groupTo
         * @param childData
         * @param childLayout
         * @param childFrom
         * @param childTo
         */ 
        public MyExpandableListViewAdapter(Context context, 
                List<? extends Map<String, ?>> groupData, int groupLayout, 
                String[] groupFrom, int[] groupTo, 
                List<? extends List<? extends Map<String, Object>>> childData, 
                int childLayout, String[] childFrom, int[] childTo) { 
            this(context, groupData, groupLayout, groupLayout, groupFrom, groupTo, 
                    childData, childLayout, childLayout, childFrom, childTo); 
        } 
     
        /**
         * 
         * @param context
         * @param groupData
         * @param expandedGroupLayout
         * @param collapsedGroupLayout
         * @param groupFrom
         * @param groupTo
         * @param childData
         * @param childLayout
         * @param lastChildLayout
         * @param childFrom
         * @param childTo
         */ 
        public MyExpandableListViewAdapter(Context context, 
                List<? extends Map<String, ?>> groupData, int expandedGroupLayout, 
                int collapsedGroupLayout, String[] groupFrom, int[] groupTo, 
                List<? extends List<? extends Map<String, Object>>> childData, 
                int childLayout, int lastChildLayout, String[] childFrom, 
                int[] childTo) { 
            mGroupData = groupData; 
            mExpandedGroupLayout = expandedGroupLayout; 
            mCollapsedGroupLayout = collapsedGroupLayout; 
            mGroupFrom = groupFrom; 
            mGroupTo = groupTo; 
            mChildData = childData; 
            mChildLayout = childLayout; 
            mLastChildLayout = lastChildLayout; 
            mChildFrom = childFrom; 
            mChildTo = childTo; 
            mInflater = (LayoutInflater) context 
                    .getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
        } 
     
        @Override 
        public Object getChild(int groupPosition, int childPosition) { 
            // 取得与指定分组、指定子项目关联的数据。 
            return mChildData.get(groupPosition).get(childPosition); 
        } 
     
        @Override 
        public long getChildId(int groupPosition, int childPosition) { 
            // 取得给定分组中给定子视图的ID。 该组ID必须在组中是唯一的。组合的ID (参见getCombinedGroupId(long)) 
            // 必须不同于其他所有ID(分组及子项目的ID)。 
            return childPosition; 
        } 
     
        @Override 
        public View getChildView(int groupPosition, int childPosition, 
                boolean isLastChild, View convertView, ViewGroup parent) { 
            // 取得显示给定分组给定子位置的数据用的视图。 
            View v; 
            if (convertView == null) { 
                v = newChildView(isLastChild, parent); 
            } else { 
                v = convertView; 
            } 
            bindChildView(v, mChildData.get(groupPosition).get(childPosition), 
                    mChildFrom, mChildTo); 
            return v; 
        } 
     
        @Override 
        public int getChildrenCount(int groupPosition) { 
            // 取得指定分组的子元素数。 
            return mChildData.get(groupPosition).size(); 
        } 
     
        @Override 
        public Object getGroup(int groupPosition) { 
            // 取得与给定分组关联的数据。 
            return mGroupData.get(groupPosition); 
        } 
     
        @Override 
        public int getGroupCount() { 
            // 取得分组数 
            return mChildData.size(); 
        } 
     
        @Override 
        public long getGroupId(int groupPosition) { 
            // 取得指定分组的ID。该组ID必须在组中是唯一的。组合的ID (参见getCombinedGroupId(long)) 
            // 必须不同于其他所有ID(分组及子项目的ID)。 
            return groupPosition; 
        } 
     
        @Override 
        public View getGroupView(int groupPosition, boolean isExpanded, 
                View convertView, ViewGroup parent) { 
            // 取得用于显示给定分组的视图。 这个方法仅返回分组的视图对象, 要想获取子元素的视图对象, 
            // 就需要调用 getChildView(int, int, boolean, View, ViewGroup)。 
            View v; 
            if (convertView == null) { 
                v = newGroupView(isExpanded, parent); 
            } else { 
                v = convertView; 
            } 
            bindGroupView(v, mGroupData.get(groupPosition), mGroupFrom, mGroupTo); 
            return v; 
        } 
     
        @Override 
        public boolean hasStableIds() { 
            // 是否指定分组视图及其子视图的ID对应的后台数据改变也会保持该ID。 
            return true; 
        } 
     
        @Override 
        public boolean isChildSelectable(int groupPosition, int childPosition) { 
            // 指定位置的子视图是否可选择。 
            return true; 
        } 
     
        /**
         * 创建新的组视图
         * 
         * @param isExpanded
         * @param parent
         * @return
         */ 
        public View newGroupView(boolean isExpanded, ViewGroup parent) { 
            return mInflater.inflate((isExpanded) ? mExpandedGroupLayout 
                    : mCollapsedGroupLayout, parent, false); 
        } 
     
        /**
         * 创建新的子视图
         * 
         * @param isLastChild
         * @param parent
         * @return
         */ 
        public View newChildView(boolean isLastChild, ViewGroup parent) { 
            return mInflater.inflate((isLastChild) ? mLastChildLayout 
                    : mChildLayout, parent, false); 
        } 
     
        /**
         * 绑定组数据
         * 
         * @param view
         * @param data
         * @param from
         * @param to
         */ 
        private void bindGroupView(View view, Map<String, ?> data, String[] from, 
                int[] to) { 
            // 绑定组视图的数据,针对Group的Layout都是TextView的情况 
            int len = to.length; 
            for (int i = 0; i < len; i++) { 
                TextView v = (TextView) view.findViewById(to[i]); 
                if (v != null) { 
                    v.setText((String) data.get(from[i])); 
                } 
            } 
        } 
     
        /**
         * 绑定子数据
         * 
         * @param view
         * @param data
         * @param from
         * @param to
         */ 
        private void bindChildView(View view, Map<String, ?> data, String[] from, 
                int[] to) { 
            TextView v = (TextView) view.findViewById(to[0]); 
            if (v != null) { 
                v.setText((String) data.get(from[0])); 
            } 
            CheckBox c = (CheckBox) view.findViewById(to[1]); 
            // View中的setTag(Onbect)表示给View添加一个格外的数据,以后可以用getTag()将这个数据取出来。 
            view.setTag(c); 
            if (c != null) { 
                if (data.get(from[1]).equals(0)) { 
                    c.setChecked(true); 
                } else { 
                    c.setChecked(false); 
                } 
            } 
        } 
     
        public void updateChildData(int groupPosition, int childPosition) { 
            int checked = (Integer) mChildData.get(groupPosition) 
                    .get(childPosition).get("childCheckBox"); 
            mChildData.get(groupPosition).get(childPosition) 
                    .remove("childCheckBox"); 
            if (checked == 0) { 
                mChildData.get(groupPosition).get(childPosition) 
                        .put("childCheckBox", 1); 
            } else if (checked == 1) { 
                mChildData.get(groupPosition).get(childPosition) 
                        .put("childCheckBox", 0); 
            } 
        } 
    } 


这里就不上图了。效果是一样的。
分享到:
上一篇:ExpandableListView扩展(BaseExpandableListAdapter的使用)
下一篇:Caused by: android.util.AndroidRuntimeException: Calling startActivity() from outside of an Activity
分享到:
评论

相关推荐

    dd命令操作简介

    dd命令很多人都会用,但是还有很多需要学习的。

    Android Studio 正式版

    Android Studio是Google专门为Android应用开发推出的一款集成开发环境(IDE),它基于IntelliJ IDEA,提供了强大的代码编辑、调试、构建以及性能优化工具。自从2013年首次发布以来,Android Studio逐渐取代了Eclipse...

    DD登录 Android考试题目.zip

    两个EditText获取数据,点击Button“DD登录”后,数据存储为XML方式,然后跳转到另外一个界面显示。点击Button“关闭界面”后,退出APP程序。 主界面中,两个EditText无论是否填写数据,都可以执行跳转。 主界面...

    Gallery3dD源代码(android4.0版原生)

    《Android 4.0 Gallery3D源代码解析与探索》 在Android系统中,Gallery3D是一款用于展示图片和视频的高效应用,特别是在Android 4.0(Ice Cream Sandwich,简称ICS)版本中,Gallery3D以其流畅的用户体验和优秀的...

    Android中DateTimePicker的实现

    String datePattern = "yyyy-MM-dd"; String timePattern = "HH:mm"; SimpleDateFormat dateFormatter = new SimpleDateFormat(datePattern, Locale.getDefault()); SimpleDateFormat timeFormatter = new ...

    android语言国际化

    - 不同地区有不同的日期和数字格式,如美国使用MM/dd/yyyy,而欧洲使用dd/MM/yyyy。Android提供了`java.text.SimpleDateFormat`和`java.util.NumberFormat`类来处理这些格式。 - 可以通过获取`Locale`对象并传入`...

    android 时间总结

    这时可以使用`SimpleDateFormat`来格式化日期和时间,例如“yyyy-MM-dd HH:mm:ss”。但同样,由于其线程不安全和性能问题,建议使用`java.time.format.DateTimeFormatter`代替。另外,对于Android API Level 26及...

    Android-AndroidToast工具类

    在Android应用开发中,`AndroidToast`工具类是一种常见的组件,用于向用户显示短暂的通知信息。这些信息通常出现在屏幕上的某个位置,展示几秒钟后自动消失,不会干扰用户的正常操作。`AndroidToast`的使用非常方便...

    android中日期输入

    可以根据需求调整日期格式,这里使用的是"YYYY-MM-DD"格式。如果你需要其他格式,可以使用`SimpleDateFormat`类。 6. **样式和主题**: Android提供了多种方式来定制`DatePicker`的样式,包括使用自定义的主题...

    Android代码-android-morphing-button

    Android button which can morph from one shape to another. You can easily extend MorphingButton to add your own behaviour. Below is example of LinearProgressButton which extends MorphingButton. ...

    Android 学习(9)DatePicker

    在实际应用中,你可能还需要考虑到不同设备和地区对日期格式的差异,以及如何将选择的日期转换成其他格式,例如`yyyy-MM-dd`,这可能需要使用`SimpleDateFormat`类。 在`DatePickerDemo`这个项目中,开发者可能创建...

    Android拦截接收短信

    SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String sendtime = format.format(date); // ... } ``` 在实际应用中,可能还需要根据这些信息进行各种操作,比如存储短信到数据库、...

    修改Android系统日期

    - `date -s "YYYY-MM-DD HH:MM:SS"`:这个命令可以用来设置系统日期和时间。例如,`date -s "2022-01-01 00:00:00"`会将时间设置为2022年1月1日的零点。 - `hwclock -w`:此命令将系统RTC(实时时钟)设置为当前...

    Android开源开发框架

    《全面解析Android开源开发框架——以white-cat-ThinkAndroid-81dd215为例》 在移动应用开发领域,Android平台因其开放性和强大的社区支持,一直是开发者们的重要选择。而一个优秀的Android开发框架,能够极大地...

    基于Java的DD记账Android手机记账APP后端源码设计

    本项目为基于Java开发的DD记账Android手机记账APP后端源码,包含203个文件,其中包括146个Java源文件、32个XML配置文件、4个偏好设置文件、4个JSP文件、3个SQL脚本文件、3个属性文件以及少量其他类型文件,旨在打造...

    Android-Android硬编码提取工具

    "Fuck-Hard-Code-dd1ed7d"这个工具很可能就是用于自动识别和抽取代码中的硬编码,帮助开发者快速定位到问题区域。使用此类工具通常包含以下几个步骤: 1. 扫描代码:工具会遍历整个项目,查找可能的硬编码,例如直接...

    Android-AndroidJSCore允许Android开发人员在自己的应用中使用JavaScript

    9. **社区和资源**:由于AndroidJSCore是开源项目,开发者可以从GitHub(如提供的ericwlange-AndroidJSCore-3dd9296)获取源码、参与贡献或查阅已有的问题和解决方案。此外,开发者社区提供了丰富的教程、示例和讨论...

    Android-AndroidTreeView用于以树结构显示数据

    在`Team-Blox-GraphView-43dd723`这个文件中,虽然名称提到了`GraphView`,但根据上下文判断,可能是与`AndroidTreeView`的某个版本或者示例项目相关。`GraphView`可能是指另一个库,用于在Android上绘制图表,可能...

    android 显示当前日期和时间

    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); String currentTimeStr = LocalDateTime.now().format(formatter); ``` 3. 创建对话框: 在Android中,我们可以使用`...

    Android 获取时间Demo

    在Android开发中,时间的获取和使用是相当常见的操作,涉及到日期、时间的显示、比较、格式化等多方面。本教程将深入探讨Android中如何获取和处理时间,以实现各种功能。 首先,Android提供了java.util.Date和java....

Global site tag (gtag.js) - Google Analytics