zoukankan      html  css  js  c++  java
  • 可展开的列表组件——ExpandableListView深入解析

    可展开的列表组件——ExpandableListView深入解析

    一、知识点 
    1、ExpandableListView常用XML属性 
    2.ExpandableListView继承BaseExpandableListAdapter后重写的各个函数详解 
    3.ExpandableListView自定义下拉图标

    二、解析 
    2.1、ExpandableListView常用XML属性

    2.1.1 设置点击item项后该item项的背景色

    //当你选中某一个item项时,该item项的背景会变色,下面的值是将该背景色设置为透明
    
    android:listSelector="#00000000"

    2.1.2 设置item项的高度

    //这个是用在item的布局文件里
    android:minHeight="50dp"

    2.1.3 拖动时背景图片问题

    //在拖动的时候背景图片消失变成黑色背景,等到拖动完毕我们自己的背景图片才显示出来
    android:scrollingCache=”false” 
    或 android:cacheColorHint=”#00000000″

    2.1.4 分割线高度

    android:dividerHeight="1dp"

    2.2ExpandableListView继承BaseExpandableListAdapter后重写的各个函数详解

    下面的代码几乎每条都给了注释,就不再赘述了。

    2.2.1 child.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout 
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:orientation="horizontal" >
    
        <TextView 
            android:id="@+id/tv"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:layout_marginLeft="10dp"
            android:textSize="18dp"
            android:text="this"
            />
    
    </LinearLayout>

    2.2.2 group.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout 
    
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:minHeight="50dp"
        android:orientation="horizontal" >
        <ImageView
            android:layout_marginLeft="10dp"
            android:layout_gravity="center_vertical"
            android:id="@+id/arrow"
            android:layout_width="25dp"
            android:layout_height="25dp"
            />
        <TextView 
            android:layout_marginLeft="10dp"
            android:id="@+id/logo"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="20dp"
            android:layout_gravity="center_vertical"
            />
    </LinearLayout>

    2.2.3 colors.xml

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <color name="gray">#BEBEBE</color>
        <color name="SeaGreen1">#54FF9F</color>
    </resources>

    2.2.4 activity_main.xml

    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
    
        >
        <ExpandableListView 
            android:id="@+id/expandlist"
            android:divider="@color/gray"
            android:childDivider="@color/SeaGreen1"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:groupIndicator="@null"
            android:listSelector="#00000000"
            android:dividerHeight="1dp"
            >
    
        </ExpandableListView>
    </LinearLayout>

    2.2.5 MyExpandableListAdapter.java

    package com.yds.example;
    
    
    import java.util.List;
    import java.util.Map;
    
    import android.content.Context;
    import android.database.DataSetObserver;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.BaseExpandableListAdapter;
    import android.widget.ImageView;
    import android.widget.TextView;
    
    public class MyExpandableListAdapter extends BaseExpandableListAdapter {
        //上下文
        Context context;
        //声明一个布局管理器对象
        LayoutInflater inflater;
        //声明一个组集合
        List<Map<String, Object>>group;
        //声明一个子元素集合
        List<List<Map<String, Object>>>child;
        //声明一个map对象
        Map<String, Object>map;
        /**
         * 自定义适配器的构造函数
         * @param context 上下文
         * @param group 组集合
         * @param child 子元素集合
         */
        public MyExpandableListAdapter(Context context,List<Map<String, Object>>group,List<List<Map<String, Object>>>child){
            //初始化上下文
            this.context = context;
            //初始化布局管理器对象
            inflater = LayoutInflater.from(context);
            //初始化组集合
            this.group = group;
            //初始化子元素集合
            this.child = child;
        }
        /**
         * ExpandableListAdapter里面的所有条目
         * 都可用吗?如果是yes,就意味着所有条目可以选择和点击了。
         * 返回值:返回True表示所有条目均可用。
         */
        @Override
        public boolean areAllItemsEnabled() {
            // TODO Auto-generated method stub
            return true;
        }
        /**
         * 获取指定组中的指定子元素数据。 
         */
        @Override
        public Object getChild(int groupPosition, int childPosition) {
            // TODO Auto-generated method stub
            /*child.get(groupPosition)是得到groupPosition处的list对象,然后
             * child.get(groupPosition).get(childPosition)得到child的map对象,然后
             * child.get(groupPosition).get(childPosition).get("Child")是得到key值
             * 为Child的值
             * */
            return child.get(groupPosition).get(childPosition).get("Child");
        }
        /**
         * 获取指定组中的指定子元素ID,这个ID在组里一定是唯一的。联合ID(getCombinedChildId(long, long))在所有条目(所有组和所有元素)中也是唯一的。
         */
        @Override
        public long getChildId(int groupPosition, int childPosition) {
            // TODO Auto-generated method stub
            /******子元素的位置********/
            return childPosition;
        }
        /**获取一个视图对象,显示指定组中的指定子元素数据。
         * @param groupPosition 组位置(该组内部含有子元素)
         * @param childPosition 子元素位置(决定返回哪个视图)
         * @param isLastChild 子元素是否处于组中的最后一个
         * @param convertView 重用已经有的视图对象,它是RecycleBin缓存机制调用getScrapView方法获取废弃已缓存的view.
         * @param parent 返回的视图(View)对象始终依附于的视图组。通俗的说是它的父视图。
         */
        @Override
        public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
            // TODO Auto-generated method stub
            ViewHolderChild viewHolderChild;
            /*当convertView为空,也就是没有废弃已缓存 view时,将执行下面方法,调用layoutinflate的
             * inflate()方法来加载一个view。
             * 如有不懂,请点击:http://blog.csdn.net/libmill/article/details/49644743
             */
            if(convertView==null){
                //重新加载布局
                convertView = inflater.inflate(R.layout.child, null);
                //初始化控件管理器(自己命名的)
                viewHolderChild = new ViewHolderChild();
                //绑定控件id
                viewHolderChild.tv = (TextView) convertView.findViewById(R.id.tv);
                /*convertView的setTag将viewHolderChild设置到Tag中,以便系统第二次绘制
                    ExpandableListView时从Tag中取出
                */
                convertView.setTag(viewHolderChild);
            }else{
                //当convertView不为空时,从Tag中取出viewHolderChild
                viewHolderChild = (ViewHolderChild) convertView.getTag();
            }
            //给子元素的TextView设置值
            viewHolderChild.tv.setText(getChild(groupPosition, childPosition).toString());
            //返回视图对象,这里是childPostion处的视图
            return convertView;
        }
        /**
         * 获取指定组中子元素的个数
         */
        @Override
        public int getChildrenCount(int groupPosition) {
            // TODO Auto-generated method stub
            return child.get(groupPosition).size();
        }
        /**
         * 从列表所有项(组或子项)中获得一个唯一的子ID号。可折叠列表要求每个元素(组或子项)在所有的子元素和组中
         * 有一个唯一的ID。本方法负责根据所给的子ID号和组ID号返回唯一的ID。此外,若hasStableIds()
         * 是true,那么必须要返回稳定的ID。
         * @param groupId 包含该子元素的组ID
         * @param childId 子元素的ID
         * @return:列表所有项(组或子项)中唯一的(和可能稳定)的子元素ID号。(译者注:ID理论上是稳定的,
         * 不会发生冲突的情况。也就是说,这个列表会有组、子元素,它们的ID都是唯一的。) 
         */
        @Override
        public long getCombinedChildId(long groupId , long childId ) {
            // TODO Auto-generated method stub
            return 0;
        }
        /**
         * 获取组ID
         * @param groupId 组ID
         * @return :组ID
         */
        @Override
        public long getCombinedGroupId(long groupId) {
            // TODO Auto-generated method stub
            return 0;
        }
        /**
         * 得到指定组的组数据
         * @param groupPosition:指定的组的位置
         * @return 返回指定组的组数据
         */
        @Override
        public Object getGroup(int groupPosition) {
            // TODO Auto-generated method stub
            /**group.get(groupPosition)获取map对象
             * group.get(groupPosition).get("Group")获取key值为Group的数据
             * **/
            return group.get(groupPosition).get("Group");
        }
        /**
         * 获取组长
         */
        @Override
        public int getGroupCount() {
            // TODO Auto-generated method stub
            return group.size();
        }
        /**
         * 获取指定组的Id
         */
        @Override
        public long getGroupId(int groupPosition) {
            // TODO Auto-generated method stub
            return groupPosition;
        }
        /**
         * 获取指定组的视图对象
         * @param groupPosition:组位置(决定返回哪个视图)
         * @param isExpanded:改组是展开状态还是伸缩状态
         * @param convertView:重用已有的视图对象
         * @return 返回指定组的视图对象
         */
        @Override
        public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
            // TODO Auto-generated method stub
            ViewHolderGroup viewHolder;
            //判断convertView是否为空,convertView是RecycleBean调用getScrapView函数得到废弃已缓存的view
            if(convertView==null){
                //初始化控件管理器对象
                viewHolder = new ViewHolderGroup();
                //重新加载布局
                convertView = inflater.inflate(R.layout.group, null);
                //给组元素绑定ID
                viewHolder.logo_tv = (TextView) convertView.findViewById(R.id.logo);
                //给组元素箭头绑定ID
                viewHolder.arrow = (ImageView) convertView.findViewById(R.id.arrow);
                //convertView将viewHolder设置到Tag中,以便再次绘制ExpandableListView时从Tag中取出viewHolder;
                convertView.setTag(viewHolder);
            }else {//如果convertView不为空,即getScrapView得到废弃已缓存的view
                //从Tag中取出之前存入的viewHolder
                viewHolder = (ViewHolderGroup) convertView.getTag();
            }
            //设置组值
            viewHolder.logo_tv.setText(getGroup(groupPosition).toString());
            //如果组是展开状态
            if (isExpanded) {
                //箭头向下
                viewHolder.arrow.setImageResource(R.drawable.arrow_down);
            }else{//如果组是伸缩状态
                //箭头向右
                viewHolder.arrow.setImageResource(R.drawable.arrow);
            }
            //返回得到的指定组的视图对象
            return convertView;
        }
        /**
         * 组和子元素是否持有稳定的ID,也就是底层数据的改变不会影响到它们。
         * @return 返回一个Boolean类型的值,如果为TRUE,意味着相同的ID永远引用相同的对象
         */
        @Override
        public boolean hasStableIds() {
            // TODO Auto-generated method stub
            return false;
        }
        /**
         * 是否选中指定位置上的子元素。
         */
        @Override
        public boolean isChildSelectable(int arg0, int arg1) {
            // TODO Auto-generated method stub
            return true;
        }
        /**
         * 如果当前适配器不包含任何数据则返回True。经常用来决定一个空视图是否应该被显示。
         * 一个典型的实现将返回表达式getCount() == 0的结果,但是由于getCount()包含了头部和尾部,适配器可能需要不同的行为。
         */
        @Override
        public boolean isEmpty() {
            // TODO Auto-generated method stub
            return false;
        }
        /**
         * 当组收缩状态的时候此方法被调用。
         */
        @Override
        public void onGroupCollapsed(int groupPosition) {
            // TODO Auto-generated method stub
    
        }
        /**
         * 当组展开状态的时候此方法被调用。
         */
        @Override
        public void onGroupExpanded(int groupPosition) {
            // TODO Auto-generated method stub
    
        }
        /**
         * 注册一个观察者(observer),当此适配器数据修改时即调用此观察者。
         * @param observer:当数据修改时通知调用的对象
         */
        @Override
        public void registerDataSetObserver(DataSetObserver observer) {
            // TODO Auto-generated method stub
    
        }
        /**
         * 取消先前通过registerDataSetObserver(DataSetObserver)方式注册进该适配器中的观察者对象。
         * @param observer 取消这个观察者的注册
         */
        @Override
        public void unregisterDataSetObserver(DataSetObserver observer) {
            // TODO Auto-generated method stub
    
        }
        /**
         * 组控件管理器
         * @author Administrator
         *
         */
        class ViewHolderGroup{
            TextView logo_tv;
            ImageView arrow;
        }
        /**
         * 子控件管理器
         * @author Administrator
         *
         */
        class ViewHolderChild{
            TextView tv;
        }
    }

    2.2.6 MainActivity.java

    package com.yds.example;
    
    
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    import android.app.Activity;
    import android.os.Bundle;
    import android.widget.ExpandableListView;
    
    public class MainActivity extends Activity {
        //声明一个可伸展的列表视图对象
        private ExpandableListView expandlist;
        //声明并初始化一个组集合对象,该集合时一个一维数组
        private List<Map<String, Object>>groupList = new ArrayList<Map<String,Object>>();
        //声明一个子元素集合对象,该集合是一个数组链表
        private List<List<Map<String, Object>>>childList = new ArrayList<List<Map<String,Object>>>();
        //声明一个子元素集合对象
        private List<Map<String, Object>>child;
        //声明一个map对象
        private Map<String, Object>map;
        //组元素值
        private String[] armTypes = new String[]{
                "WORD", "EXCEL", "EMAIL", "PPT"
        };
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            // TODO Auto-generated method stub
            super.onCreate(savedInstanceState);
            //加载布局
            setContentView(R.layout.activity_main);
            //给组赋值
            for (int i = 0; i < armTypes.length; i++) {
                //每次都要初始化map对象
                map = new HashMap<String, Object>();
                //将组值放入key为Group的map中
                map.put("Group", armTypes[i]);
                //将map添加到组集合中
                groupList.add(map);
            }
            //给每组的子元素赋值
            for (int j = 0; j < 4; j++) {
                //每次初始化子集合对象。该对象是一个一维数组
                child = new ArrayList<Map<String,Object>>();
                //每个组下面有25个子元素
                for (int i = 0; i < 25; i++) {
                    //初始化map对象
                    map = new HashMap<String, Object>();
                    //将子元素的值放入key值为Child的map中
                    map.put("Child", "this is "+i+" example");
                    //将map添加到一维数组中
                    child.add(map);
                }
                //将一维数组添加到集合中
                childList.add(child);
            }
            //可伸展的列表视图绑定ID
            expandlist = (ExpandableListView) findViewById(R.id.expandlist);
            //声明并初始化一个adapter
            MyExpandableListAdapter adapter = new MyExpandableListAdapter(MainActivity.this,groupList,childList);
            //可伸展的列表视图加载adapter
            expandlist.setAdapter(adapter);
        }
    }

    三、结果截图:

  • 相关阅读:
    C#数据结构一:基础知识
    使用工厂方法模式实现多数据库WinForm手机号码查询器(附源码)
    我的个人年度总结
    CutePsWheel javascript libary:控制输入文本框为可使用滚轮控制的js库
    CSS制作无图片圆角矩形
    将SqlServer数据库转换Sqlite的工具
    原创电子书:C#难点逐个击破
    (译)在非IE浏览器中实现“灰阶化”
    extjs 记录一下
    Ext.Window相关
  • 原文地址:https://www.cnblogs.com/ityizhainan/p/6026650.html
Copyright © 2011-2022 走看看