Android进阶:手风琴特效—步骤2: ExpandableListView(可拓展的ListView)

ExpandableListView的基本介绍

作者:CnPeng
https://www.jianshu.com/p/05df9c17a1d8

1 什么是ExpandableListView?有啥作用?

首先看一张ExpandableListView 的继承关系图:

ExpandableListView的继承关系

一种用于垂直滚动展示两级列表的视图,和 ListView 的不同之处就是它可以展示两级列表,分组可以单独展开显示子选项。这些选项的数据是通过 ExpandableListAdapter 关联的。

  • 与ListView的区别

    ExpandableListView与ListView的区别在于,ExpandableListView 对列表项进行了分组,每个分组中又可以显示具体的子项目。就像QQ中的好友分组,我们登录QQ之后,点击联系人就会显示所有的好友分组,然后点击某个分组,就可以展示这个分组中具体的联系人,这种界面就可以用ExpandableListView 来实现。

    2.主要应用场景

  • 联系人分组

2 ExpandableListAdapter

根据上面的 “ExpandableListView 的继承关系” 图可以看出,ExpandableListView本质是一个AdapterView,既然是AdapterView,那么在展示数据的时候就需要使用到Adapter ——在展示ExpandableListView 的数据时使用就是ExpandableListAdapter。

ExpandableListAdapter的继承关系如下图:

通常我们在展示ExpandableListView 的数据时,使用比较多的方式及adapter是:

  • 直接自定义Adapter继承BaseExpandableListAdapter.
    这种方式的关键是实现四个方法:getCroupCount() 返回组的数量;getCroupView() 返回组的view对象;getChildCount() ,返回某组的子View数量; getChildView() 返回某组中的子view.
  • 使用SimpleExpandableListAdapter将两个List集合包装成ExpandableListAdapter
  • 使用SimpleCursorTreeAdapter 将Cursor中的数据包装成SimpleCursorTreeAdapter

ExpandableListView的常用属性

  1. groupIndicator(分组的指示器)
  2. childIndicator(每一个分组下面的子item的指示器)
  3. childDivider(每一个子item下面设置分割线)

(1)XML属性

由于ExpandableListView 继承自ListView,所以ListView 可用的属性,ExpandableListView 也可以使用,除此之外,还有如下属性(这里只列举2个属性,其他的可以自己查看文档
https://developer.android.google.cn/reference/android/widget/ExpandableListView.html

1) android:groupIndicator 和android:childIndicator

  • android:groupIndicator
    组指示器。取值可以是任意的Drawable对象。显示在 该分组的最左侧。如果不设置的话,默认是一个向下的箭头,点击展开内容之后会变成向上的箭头。如下图:

Paste_Image.png

  • android:childIndicator
    子条目指示器。取值可以是任意的Drawable 对象。显示在分组中的每一个 子条目 的最左侧。没有默认图标。

2) 如何更改indicator

如果你想更改 groupIndicator 或者 childIndicator , 可以将值设置成一个selector。具体如下:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/weixin_friend" android:state_expanded="true"/>
    <item android:drawable="@drawable/xiangguan"/>
</selector>

运行效果如下:

3)设置和更改indicator时的注意事项:

A
默认情况下,指示器会覆盖组条目内容,就向下图中的这个样子。为了避免这种情况,我们就需要手动的在布局文件中或者代码中将 组条目向右移,以保证条目内容不被覆盖。

 

B
如果想取消 默认的 gropIndicator,可以将它赋值为"@null",即:android:groupIndicator="@null"。这样就不会再显示groupIndicator了

C
替换默认indicator时,我们使用了一个selector,在编写这个selector时需要特别注意,我们用的状态是 :state_expanded,这个状态在编写的时候不会自动补全,必须完全手动拼写!!

(2)主要方法及监听器

  • collapseGroup( int position)

    收起 position 位置的分组

  • expandGroup(int position)

展开position位置的分组

  • isGroupExpanded(int position)

判断position位置的分组是否展开

  • setAdapter(ExpandableListAdapter adapter)

给ExpandableListView 设置适配器

  • setOnChildClickListener(OnChildClickListener listener)

设置分组中子条目的点击监听器

  • setOnGroupClickListener(OnGroupClickListener listener)

设置分组的点击监听器

  • setOnGroupCollapseListener(OnGroupCollapseListener listener)

设置分组收起的监听器

  • setOnGroupExpandListener(OnGroupExpandListener listener)

设置分组展开的监听器

4 完整示例代码:

该示例代码的实现的效果是:

  • 取消默认的 groupIndicator
  • 在组条目末尾自定义 展开/收起 的指示器
  • 拦截分组的点击事件
  • 默认展开第一个分组
  • 处理分组中子条目的点击事件
  • 处理分组子条目中的强焦点控件的点击事件(这里加入的是CheckBox)

最终效果gif图:

ExpandableListView.gif


A ExpandableListViewActivity.java

/**
 * Created by CnPeng on 2017/1/21.
 * <p>
 * 使用BaseExpandableLsitAdapter 展示ExpandableLsitView 的具体内容
 */

public class ExpandableListViewActivity extends AppCompatActivity {

    private View.OnClickListener ivGoToChildClickListener;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_expandablelv);

        init();
    }

    private void init() {
        final ExpandableListView elv01 = (ExpandableListView) findViewById(R.id.elv_01);

        //模拟数据(数组,集合都可以,这里使用数组)
        final String[] classes = new String[]{"一班", "二班", "三班", "四班","五班"};
        final String[][] students = new String[][]{{"张三1", "李四1", "王五1", "赵六1", "钱七1", "高八1"}, {"张三1", "李四1", "王五1", 
                "赵六1", "钱七1", "高八1"}, {"张三1", "李四1", "王五1", "赵六1", "钱七1", "高八1"}, {"张三1", "李四1", "王五1", "赵六1", "钱七1",
                "高八1"},{}};

        //自定义 展开/收起  图标的点击事件。position和 isExpand 都是通过tag 传递的
        ivGoToChildClickListener = new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //获取被点击图标所在的group的索引
                Map<String, Object> map = (Map<String, Object>) v.getTag();
                int groupPosition = (int) map.get("groupPosition");
//                boolean isExpand = (boolean) map.get("isExpanded");   //这种是通过tag传值
                boolean isExpand = elv01.isGroupExpanded(groupPosition);    //判断分组是否展开

                if (isExpand) {
                    elv01.collapseGroup(groupPosition);
                } else {
                    elv01.expandGroup(groupPosition);
                }
            }
        };

        //创建并设置适配器
        MyExpandableListAdapter adapter = new MyExpandableListAdapter(classes, students, this, 
                ivGoToChildClickListener);
        elv01.setAdapter(adapter);
        
        //默认展开第一个分组
        elv01.expandGroup(0);

        //展开某个分组时,并关闭其他分组。注意这里设置的是 ExpandListener
        elv01.setOnGroupExpandListener(new ExpandableListView.OnGroupExpandListener() {
            @Override
            public void onGroupExpand(int groupPosition) {
                //遍历 group 的数组(或集合),判断当前被点击的位置与哪个组索引一致,不一致就合并起来。
                for (int i = 0; i < classes.length; i++) {
                    if (i != groupPosition) {
                        elv01.collapseGroup(i); //收起某个指定的组
                    }
                }
            }
        });

        //点击某个分组时,跳转到指定Activity
        elv01.setOnGroupClickListener(new ExpandableListView.OnGroupClickListener() {
            @Override
            public boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long id) {
                Toast.makeText(ExpandableListViewActivity.this, "组被点击了,跳转到具体的Activity", Toast.LENGTH_SHORT).show();
                return true;    //拦截点击事件,不再处理展开或者收起
            }
        });

        //某个分组中的子View被点击时的事件
        elv01.setOnChildClickListener(new ExpandableListView.OnChildClickListener() {
            @Override
            public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition,
                                        long id) {

                Toast.makeText(ExpandableListViewActivity.this, "组中的条目被点击:" + classes[groupPosition] + "的" +
                        students[groupPosition][childPosition] + "放学后到校长办公室", Toast.LENGTH_SHORT).show();
                return false;
            }
        });

    }
}

B 布局文件 activity_expandablelv.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="match_parent"
              android:orientation="vertical">
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:padding="@dimen/dp10"
        android:text="扩展BaseExpandableListAdapter展示ExpandableListView"/>

    <!--这个默认的GroupIndicator 还是直接置空吧,默认的太鸡肋-->
    <ExpandableListView
        android:id="@+id/elv_01"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:divider="#ff0000"
        android:dividerHeight="@dimen/dp2"
        android:groupIndicator="@null">

    </ExpandableListView>
</LinearLayout>

C 适配器 MyExpandableListAdapter.java


/**
 * Created by CnPeng on 2017/1/21.
 * <p>
 * 自定义ExpandableListAdapter展示ExpandableListView的内容
 */

public class MyExpandableListAdapter extends BaseExpandableListAdapter {
    private String[]   classes;
    private String[][] stuents;
    private Context    context;
    View.OnClickListener ivGoToChildClickListener;

    public MyExpandableListAdapter() {

    }

    public MyExpandableListAdapter(String[] classes, String[][] stuents, Context context,
                                   View.OnClickListener ivGoToChildClickListener) {
        this.classes = classes;
        this.stuents = stuents;
        this.context = context;
        this.ivGoToChildClickListener = ivGoToChildClickListener;
    }

    @Override
    public int getGroupCount() {    //组的数量
        return classes.length;
    }

    @Override
    public int getChildrenCount(int groupPosition) {    //某组中子项数量
        return stuents[groupPosition].length;
    }

    @Override
    public Object getGroup(int groupPosition) {     //某组
        return classes[groupPosition];
    }

    @Override
    public Object getChild(int groupPosition, int childPosition) {  //某子项
        return stuents[groupPosition][childPosition];
    }

    @Override
    public long getGroupId(int groupPosition) {
        return groupPosition;
    }

    @Override
    public long getChildId(int groupPosition, int childPosition) {
        return childPosition;
    }


    @Override
    public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
        GroupHold groupHold;
        if (convertView == null) {
            convertView = LayoutInflater.from(context).inflate(R.layout.item_elv_group, null);
            groupHold = new GroupHold();
            groupHold.tvGroupName = (TextView) convertView.findViewById(R.id.tv_groupName);
            groupHold.ivGoToChildLv = (ImageView) convertView.findViewById(R.id.iv_goToChildLV);

            convertView.setTag(groupHold);

        } else {
            groupHold = (GroupHold) convertView.getTag();

        }

        String groupName = classes[groupPosition];
        groupHold.tvGroupName.setText(groupName);

        //取消默认的groupIndicator后根据方法中传入的isExpand判断组是否展开并动态自定义指示器
        if (isExpanded) {   //如果组展开
            groupHold.ivGoToChildLv.setImageResource(R.drawable.delete);
        } else {
            groupHold.ivGoToChildLv.setImageResource(R.drawable.send_btn_add);
        }

        //setTag() 方法接收的类型是object ,所以可将position和converView先封装在Map中。Bundle中无法封装view,所以不用bundle
        Map<String, Object> tagMap = new HashMap<>();
        tagMap.put("groupPosition", groupPosition);
        tagMap.put("isExpanded", isExpanded);
        groupHold.ivGoToChildLv.setTag(tagMap);

        //图标的点击事件
        groupHold.ivGoToChildLv.setOnClickListener(ivGoToChildClickListener);

        return convertView;
    }

    @Override
    public View getChildView(final int groupPosition, final int childPosition, boolean isLastChild, View convertView,
                             ViewGroup parent) {
        ChildHold childHold;
        if (convertView == null) {
            convertView = LayoutInflater.from(context).inflate(R.layout.item_elv_child, null);
            childHold = new ChildHold();
            childHold.tvChildName = (TextView) convertView.findViewById(R.id.tv_elv_childName);
            childHold.cbElvChild = (CheckBox) convertView.findViewById(R.id.cb_elvChild);
            convertView.setTag(childHold);
        } else {
            childHold = (ChildHold) convertView.getTag();
        }

        String childName = stuents[groupPosition][childPosition];
        childHold.tvChildName.setText(childName);

        childHold.cbElvChild.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                if (isChecked) {
                    Toast.makeText(context, "条目选中:" + classes[groupPosition] + "的" +
                            stuents[groupPosition][childPosition] + "被选中了", Toast.LENGTH_SHORT).show();
                } else {
                    Toast.makeText(context, "条目选中:" + classes[groupPosition] + "的" +
                            stuents[groupPosition][childPosition] + "被取消选中了", Toast.LENGTH_SHORT).show();
                }
            }
        });

        return convertView;
    }

    @Override
    public boolean isChildSelectable(int groupPosition, int childPosition) {
        return true;    //默认返回false,改成true表示组中的子条目可以被点击选中
    }

    @Override
    public boolean hasStableIds() {
        return true;
    }

    class GroupHold {
        TextView  tvGroupName;
        ImageView ivGoToChildLv;
    }

    class ChildHold {
        TextView tvChildName;
        CheckBox cbElvChild;
    }
}

D 分组的布局 item_elv_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:gravity="center_vertical"
              android:orientation="horizontal">
    <TextView
        android:id="@+id/tv_groupName"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:padding="@dimen/dp10"
        android:text="班级"/>

    <ImageView
        android:id="@+id/iv_goToChildLV"
        android:layout_width="@dimen/dp40"
        android:layout_height="@dimen/dp20"
        android:src="@drawable/arrow"/>
</LinearLayout>

E 分组中子条目的布局文件 item_elv_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="match_parent"
              android:orientation="horizontal"
              android:paddingLeft="@dimen/dp15">
    <!--要取消CheckBox焦点,防止争抢条目的焦点-->
    <CheckBox
        android:id="@+id/cb_elvChild"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:focusable="false"/>
    <TextView
        android:id="@+id/tv_elv_childName"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="@dimen/dp10"/>

</LinearLayout>

5 总结:

A
groupIndicator 以及childIndicator 太鸡肋了,直接赋值为 @null 屏蔽掉吧

B
如果列表的条目中有强焦点的控件,如checkBox ,为了避免抢走条目焦点,需要取消他们的焦点:focusale=”false”

C
如果在Adapter中如果想知道当前分组的展开/收起状态,那么可以从 adpater 的 getGroupView() 方法中获取,其中一个参数就是isExpand;如果在activity 等中可以调用 isGroupExpandable(position)

D
setTag(object) 方法中的参数是object类型的,如果需要传递多个信息可以使用map 或者bundle等进行封装,但是bundle中不能封装view对象

E
ExpandListView 类中的 collapseGroup(position) 、expandGroup(position) 作用分别是收起 、展开 position位置的分组。

F
监听分组的展开/收起事件时使用 onGroupExpandListener();

G
监听分组的点击事件时使用 onGroupClickListener() , 该监听器默认返回false, 会去处理分组的展开/收起。如果我们点击后不需要处理 展开/收起 的事件就返回true.(返回true 表示事件被拦截)

H
在处理自定义的 groupIndicator 的点击事件时,使用到了回调。相关知识可以参考我的另一篇文章:http://www.jianshu.com/p/eb226c340450

案例2:

目录结构

建立布局:

activity_main.xml 中新建一个ExpandableListView

<?xml version="1.0" encoding="utf-8"?>
<ExpandableListView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/id_expandableLv"
    android:childDivider="#414145"
    tools:context=".MainActivity">
</ExpandableListView>

item_parent_list.xml 新建父布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="56dp">
<ImageView
    android:id="@+id/item_parent_iv"
    android:layout_width="30dp"
    android:layout_height="30dp"
    android:layout_marginStart="10dp"
    tools:background="@drawable/indicator_expand"
    android:layout_gravity="center_vertical"/>
<TextView
    android:id="@+id/item_parent_tv"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_marginStart="10dp"
    android:textStyle="bold"
    android:textSize="25dp"
    android:gravity="center_vertical"
    tools:text="Android"/>
</LinearLayout>

item_child_list.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="match_parent"
    xmlns:tools="http://schemas.android.com/tools"
    android:orientation="horizontal">
    <TextView
        android:id="@+id/item_child_tv"
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:layout_marginStart="20dp"
        android:gravity="center_vertical"
        android:textSize="20dp"
        android:textStyle="bold"
        tools:text="Andorid....."/>
</LinearLayout>

在drawable文件夹中 新建selector indicator_group.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/indicator_expand" android:state_selected="true"/>
    <item android:drawable="@drawable/indicator_collapse"/>
</selector>

数据封装类bean

Chapter.java//父item的数据封装类

import java.util.ArrayList;
import java.util.List;

/**
 * 父布局的数据封装
 */
public class Chapter {
    private  String name;
    private  int id;
    private List<ChapterItem> children=new ArrayList<>();

    public Chapter() {
    }

    public Chapter( int id,String name) {
        this.name = name;
        this.id = id;
    }
    //添加子item1
    public void addChild(ChapterItem child){
        children.add(child);
        child.setPid(getId());
    }
    //添加子item方法2
    public void addChild(int id,String childName){
        ChapterItem chapterItem=new ChapterItem(id,childName);
        chapterItem.setPid(getId());
        children.add(chapterItem);
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public List<ChapterItem> getChildren() {
        return children;
    }

    public void setChildren(List<ChapterItem> children) {
        this.children = children;
    }
}

ChapterItem.java//子item的数据封装


/**
 * 子布局的数据封装
 */
public class ChapterItem {
   private String name;
   private int id;
   private int pid;

    public ChapterItem() {
    }

    public ChapterItem( int id,String name) {
        this.name = name;
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public int getPid() {
        return pid;
    }

    public void setPid(int pid) {
        this.pid = pid;
    }
}

ChaperLab.java//模拟数据

import java.util.ArrayList;
import java.util.List;

/**
 * 模拟数据
 */
public class ChapterLab {
    public  static  List<Chapter> generateDatas() {
        List<Chapter> chapters = new ArrayList<>();

        Chapter root1 = new Chapter(1, "Android");
        Chapter root2 = new Chapter(2, "IOS");
        Chapter root3 = new Chapter(3, "Unity 3D");
        Chapter root4 = new Chapter(4, "Cocos2d-x");
        root1.addChild(1, "PullToRefresh");
        root1.addChild(2, "Android 8.0通知栏解决方案");
        root1.addChild(4, "Android 与WebView的js交互");
        root1.addChild(8, "Android UiAutomator 2.0 入门实战");
        root1.addChild(10, "移动端音频视频入门");

        root2.addChild(11, "iOS开发之LeanCloud");
        root2.addChild(12, "iOS开发之传感器");
        root2.addChild(13, "iOS开发之网络协议");
        root2.addChild(14, "iOS之分享集成");
        root2.addChild(15, "iOS之FTP上传");


        root3.addChild(16, "Unity 3D 翻牌游戏开发");
        root3.addChild(17, "Unity 3D基础之变体Transform");
        root3.addChild(20, "带你开发类似Pokemon Go的AR游戏");
        root3.addChild(21, "Unity 3D游戏开发之脚本系统");
        root3.addChild(22, "Unity 3D地形编辑器");


        root4.addChild(25, "Cocos2d-x游戏之七夕女神抓捕计划");
        root4.addChild(26, "Cocos2d-x游戏开发初体验-C++篇");
        root4.addChild(27, "Cocos2d-x全民俄罗斯");
        root4.addChild(28, "Cocos2d-x坦克大战");
        root4.addChild(30, "新春特辑-Cocos抢红包");


        chapters.add(root1);
        chapters.add(root2);
        chapters.add(root3);
        chapters.add(root4);

        return chapters;
    }
}

适配器封装类

ChapterAdapter.java//适配器封装


import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseExpandableListAdapter;
import android.widget.ImageView;
import android.widget.TextView;

import com.demo.expandablelistviewdemo.R;
import com.demo.expandablelistviewdemo.bean.Chapter;

import java.util.List;

/**
 * 适配器数据封装
 */
public class ChapterAdapter extends BaseExpandableListAdapter {
    private Context context;//上下文
    private List<Chapter> mData;//显示的数据
    private LayoutInflater mInflater;

    public ChapterAdapter(Context context,List<Chapter> mData) {
        this.mData=mData;
        this.context = context;
        mInflater=LayoutInflater.from(context);
    }

    //父item的数目
    @Override
    public int getGroupCount() {
        return mData.size();
    }

    //每一个父item下子item的数目
    @Override
    public int getChildrenCount(int groupPosition) {
        return mData.get(groupPosition).getChildren().size();
    }

    //父item的位置
    @Override
    public Object getGroup(int groupPosition) {
        return mData.get(groupPosition);
    }

    //每一个父item下子item的位置
    @Override
    public Object getChild(int groupPosition, int childPosition) {
        return mData.get(groupPosition).getChildren().get(childPosition);
    }
    //父item的id
    @Override
    public long getGroupId(int groupPosition) {
        return groupPosition;
    }

    @Override
    public long getChildId(int groupPosition, int childPosition) {
        return childPosition;
    }

    @Override
    public boolean hasStableIds() {
        return false;
    }
    //父item的布局设置
    @Override
    public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
        ParentViewHolder vh;
        if(convertView==null){
            vh =new ParentViewHolder();
           convertView=mInflater.inflate(R.layout.item_parent_list,parent,false);
            vh.parent_item_iv=convertView.findViewById(R.id.item_parent_iv);
            vh.parent_item_tv=convertView.findViewById(R.id.item_parent_tv);
           convertView.setTag(vh);
       }
       else{
            vh= (ParentViewHolder) convertView.getTag();
       }
        vh.parent_item_tv.setText(mData.get(groupPosition).getName());
        vh.parent_item_iv.setSelected(isExpanded);//是否为展开
        vh.parent_item_iv.setImageResource(R.drawable.indicator_group);
        return convertView;
    }

    //子item的布局设置
    @Override
    public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
        ChildViewHolder vh;
        if(convertView==null){
            vh =new ChildViewHolder();
            convertView=mInflater.inflate(R.layout.item_child_list,parent,false);
            vh.chlid_item_tv=convertView.findViewById(R.id.item_child_tv);
            convertView.setTag(vh);
        }
        else{
            vh= (ChildViewHolder) convertView.getTag();
        }
        vh.chlid_item_tv.setText(mData.get(groupPosition).getChildren().get(childPosition).getName());
        return convertView;
    }
    //控制child不可点击
    @Override
    public boolean isChildSelectable(int groupPosition, int childPosition) {
        return true;
    }
    private static class ParentViewHolder{
        ImageView parent_item_iv;
        TextView parent_item_tv;
    }
    private static class ChildViewHolder{
        TextView chlid_item_tv;
    }
}

MainActivity.java 具体实现

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.ExpandableListView;

import com.demo.expandablelistviewdemo.adapter.ChapterAdapter;
import com.demo.expandablelistviewdemo.bean.Chapter;
import com.demo.expandablelistviewdemo.bean.ChapterLab;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {

    private ExpandableListView expandableListView;
    private ChapterAdapter adapter;
    private List<Chapter> mDatas = new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        expandableListView = findViewById(R.id.id_expandableLv);
        //生成模拟数据
         mDatas= ChapterLab.generateDatas();
        adapter=new ChapterAdapter(this,mDatas);
        expandableListView.setAdapter(adapter);
        initEvents();//添加事件
    }

    private void initEvents() {
        //点击父item的监听
        expandableListView.setOnGroupClickListener(new ExpandableListView.OnGroupClickListener() {
            @Override
            public boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long id) {
                Log.e("TAG","onGroupClick groupPosition"+groupPosition+" id="+id);
                return false;
            }
        });
        //点击子item的监听
        expandableListView.setOnChildClickListener(new ExpandableListView.OnChildClickListener() {

            @Override
            public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) {
                Log.e("TAG","onChildClick groupPosition"+groupPosition+" childPosition="+childPosition+" id="+id);

                return false;
            }
        });
        //点击父item收缩的监听
        expandableListView.setOnGroupCollapseListener(new ExpandableListView.OnGroupCollapseListener() {
            @Override
            public void onGroupCollapse(int groupPosition) {
                Log.e("TAG","onGroupCollapse groupPosition="+groupPosition);
            }
        });
        //点击父item展开的监听
        expandableListView.setOnGroupExpandListener(new ExpandableListView.OnGroupExpandListener() {
            @Override
            public void onGroupExpand(int groupPosition) {
                Log.e("TAG","onGroupExpand groupPosition="+groupPosition);
            }
        });
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值