ExpandableListView--------可展开的ListView(自定义箭头)

今天有点儿闲,闲得无聊就写了个ExpandableListView。。现在recyclerView逐渐已经代替ListView了。不知道ExpandableListView还能有多远。

首先介绍一下ExpandableListView吧:
常见使用场景: qq好友列表,各种分组。点击某个分组展开查看子条目。

实现方法:和Listview一样,在布局中使用ExpandableListView。然后自定义适配器,继承BaseExpandableListAdapter。

效果图:ExpandableListView--------可展开的ListView(自定义箭头)_第1张图片

下面是代码部分:


1.布局

布局很简单 就是只有一个ExpandableListView

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="${relativePackage}.${activityClass}" >

    
    

    <ExpandableListView
        android:id="@+id/expandableLv"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:groupIndicator="@null" />

RelativeLayout>

安卓系统会默认显示小箭头,用来展示当前的父条目是否展开,如果想去掉默认的小箭头,添加
android:groupIndicator=”@null”属性即可。


2.适配器

自定义Adapter继承BaseExpandableListAdapter

public class MyAdapter extends BaseExpandableListAdapter {

    private Context context;
    private List> childList;// 子条目
    private ArrayList parentList;// 父条目

    public MyAdapter(Context context, List> childList,
            ArrayList parentList) {
        super();
        this.context = context;
        this.childList = childList;
        this.parentList = parentList;
    }

    /**
     * 返回父条目的个数
     */
    @Override
    public int getGroupCount() {
        // TODO Auto-generated method stub
        return parentList.size();
    }

    /**
     * 返回当前父条目中子条目的个数 展开子条目时调用
     */
    @Override
    public int getChildrenCount(int groupPosition) {
        // TODO Auto-generated method stub
        return childList.get(groupPosition).size();
    }

    /**
     * 返回父条目对象
     */
    @Override
    public Object getGroup(int groupPosition) {
        // TODO Auto-generated method stub
        return parentList.get(groupPosition);
    }

    /**
     * 返回每一个子条目对象(与要显示的内容无关)
     */
    @Override
    public Object getChild(int groupPosition, int childPosition) {
        // TODO Auto-generated method stub
        return childList.get(groupPosition).get(childPosition);
    }

    /**
     * 返回父条目的id 默认使用索引值
     */
    @Override
    public long getGroupId(int groupPosition) {
        // TODO Auto-generated method stub
        return groupPosition;
    }

    /**
     * 返回子条目的id 默认使用索引值
     */
    @Override
    public long getChildId(int groupPosition, int childPosition) {
        // TODO Auto-generated method stub
        return childPosition;
    }

    @Override
    public boolean hasStableIds() {
        // TODO Auto-generated method stub
        return false;
    }

    @Override
    public View getGroupView(int groupPosition, boolean isExpanded,
            View convertView, ViewGroup parent) {
        ParentViewHolder holder = null;
        if (convertView == null) {
            convertView = View.inflate(context, R.layout.exlv_parent, null);
            holder = new ParentViewHolder();
            holder.tv = (TextView) convertView.findViewById(R.id.tv_parent);
            convertView.setTag(holder);
        } else {
            holder = (ParentViewHolder) convertView.getTag();
        }
        holder.tv.setText(parentList.get(groupPosition).tittle);
        return convertView;
    }

    @Override
    public View getChildView(int groupPosition, int childPosition,
            boolean isLastChild, View convertView, ViewGroup parent) {
        ChildViewHolder holder = null;
        if (convertView == null) {
            convertView = View.inflate(context, R.layout.exlv_children, null);
            holder = new ChildViewHolder();
            holder.iv = (ImageView) convertView.findViewById(R.id.iv_child);
            holder.tv = (TextView) convertView.findViewById(R.id.tv_child);
            convertView.setTag(holder);
        } else {
            holder = (ChildViewHolder) convertView.getTag();

        }
        holder.tv
                .setText(childList.get(groupPosition).get(childPosition).tittle);
        return convertView;
    }

    /**
     * 子条目是否可以选中
     */
    @Override
    public boolean isChildSelectable(int groupPosition, int childPosition) {
        // TODO Auto-generated method stub
        return true;
    }

    public class ChildViewHolder {
        ImageView iv;
        TextView tv;
    }

    public class ParentViewHolder {
        TextView tv;
    }
}

传参方式也同ListView。使用构造方法把组条目要显示的数据和子条目的数据传到适配器中。数据类型不限,可以是数组、map、list。需要重写的方法相对于BaseAdapter差不多,多了一些特殊的方法,看方法名就很容易理解。代码中也添加了注释。
这里的父条目的布局只有一个Textview,子条目的布局包含一个ImageView和一个TextView。


3.添加适配器

创建数据源:

parentList = new ArrayList();
        for (int i = 0; i < 5; i++) {
            parentList.add(new ParentItemBean("第" + i + "条父条目", i));
        }
        childList = new ArrayList>();
        for (int i = 0; i < 4; i++) {
            ArrayList list = new ArrayList();
            if (i % 2 == 0) {
                list.add(new ChildItemBean("", "哈哈哈" + i));
                list.add(new ChildItemBean("", "hhhh" + i));
            } else {
                list.add(new ChildItemBean("", "这就" + i));
                list.add(new ChildItemBean("", "子条目有" + i));
                list.add(new ChildItemBean("", "你好吗" + i));
                list.add(new ChildItemBean("", "呀咿呀咿呀有有" + i));
            }
            childList.add(list);
        }
        childList.add(new ArrayList());

子条目的数据源的类型为

ArrayList<ArrayList<ChildItemBean>> childList;

每一个子条目都放在一个条目组中作为父条目的展开项。

这里需要注意的是:父条目的条数与子条目的所在的集合的条数要一致,如果父条目的条数大于子条目的组数(比如有7个父条目,只有6组子条目),当点击多余的条目时,就会出现越界异常。对于上面的例子来说,就是childlist的数量于parentList的大小相等。那如果要实现父条目中无展开数据数据肿么办?传空的集合即可。也就是上面代码的最后一行,创建一个空的子条目集合。点击父条目后,无展开数据,并且不会报错。


4.设置适配器

exLv = (ExpandableListView) this.findViewById(R.id.expandableLv);
        MyAdapter adapter = new MyAdapter(this, childList, parentList);
        exLv.setAdapter(adapter);
        exLv.setOnChildClickListener(new OnChildClickListener() {

            @Override
            public boolean onChildClick(ExpandableListView parent, View v,
                    int groupPosition, int childPosition, long id) {
                // TODO Auto-generated method stub
                Toast.makeText(
                        MainActivity.this,
                        "父级条目:" + groupPosition + "     子条目:" + childPosition
                                + "    id:" + id, 1).show();
                return false;
            }
        });
        exLv.setOnGroupClickListener(new OnGroupClickListener() {

            @Override
            public boolean onGroupClick(ExpandableListView parent, View v,
                    int groupPosition, long id) {
                // TODO Auto-generated method stub
                Toast.makeText(MainActivity.this,
                        "父级条目:" + groupPosition + "    id:" + id, 1).show();
                return false;
            }
        });

ExpandableListView还提供了父条目和子条目的点击事件监听。分别是OnGroupClickListener和OnChildClickListener。

设置展开某个父条目:

  // 展开某个父条目
 exLv.expandGroup(3);

设置展关闭某个父条目:

// 关闭某个父条目
exLv.collapseGroup(3);

自定义展开收缩时的箭头显示状态:

网上查了一些修改指示箭头状态的方法,有人说通过自定义selector,讲系统默认的indicator使用的图片资源修改为自定义的selector即可。

但是我试了一下,在selector中没有找到android: state_expanded=”false” 这条属性。所以这种方法暂时是不可取的。。

还有一种方法,隐藏系统默认的箭头,使用imageView代替。然后根据当前父条目的展开状态来填充不同的图片。

首先设置系统默认的indicator的背景为空:在ExpandableListView中设置以下属性:

android:groupIndicator="@null"

然后在Adaptor的getGroupView方法中,根据展开状态来设置不同的图片资源。

public View getGroupView(int groupPosition, boolean isExpanded,
            View convertView, ViewGroup parent) {
        ParentViewHolder holder = null;
        if (convertView == null) {
            convertView = View.inflate(context, R.layout.exlv_parent, null);
            holder = new ParentViewHolder();
            holder.tv = (TextView) convertView.findViewById(R.id.tv_parent);
            holder.iv_indicator = (ImageView) convertView
                    .findViewById(R.id.iv_Indicator);
            convertView.setTag(holder);
        } else {
            holder = (ParentViewHolder) convertView.getTag();
        }
        // 根据当前父条目的展开状态来设置不同的图片
        if (isExpanded) {
            // 条目展开,设置向下的箭头
            holder.iv_indicator.setImageDrawable(context.getResources()
                    .getDrawable(R.drawable.jiantou2));
        } else {
            // 条目未展开,设置向上的箭头
            holder.iv_indicator.setImageDrawable(context.getResources()
                    .getDrawable(R.drawable.jiantou));

        return convertView;

大功告成,来看一下效果:

ExpandableListView--------可展开的ListView(自定义箭头)_第2张图片


你可能感兴趣的:(安卓基础组件)