玩转ExpandableListView

参考资料

https://blog.csdn.net/yaya_soft/article/details/25796453
https://blog.csdn.net/benweizhu/article/details/6871244

前言

现在android开发经常把使用ListView改为使用RecyclerView,实话实说,RecyclerView确实非常好用。但在某些情况下我还是倾向于使用ListView。但这次我不是用ListView,而是它的子类ExpandableListView。如图,我需要实现两个ListView的嵌套。
这里写图片描述
能看懂?那好,接下来代码实现

视图

main.xml

            <ExpandableListView
                android:layout_below="@id/source_company_number_text"
                android:id="@+id/source_company_list"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content">
            </ExpandableListView>

            <TextView
                android:id="@+id/source_more"
                android:layout_below="@+id/source_company_list"
                android:textColor="@color/blue"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="查看更多"
                android:layout_centerHorizontal="true"
                />

group_date.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">

    <TextView
        android:id="@+id/gruop_date"
        android:layout_width="match_parent"
        android:layout_height="@dimen/dp_38_y"
        android:text="2018.1.1"
        />
</LinearLayout>

child_detail.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"
    >

    <TextView
        android:layout_marginLeft="@dimen/dp_50_x"
        android:id="@+id/child_time"
        android:layout_width="wrap_content"
        android:layout_height="@dimen/dp_34_y"
        android:text="12:00"
        android:gravity="center"
        />

    <TextView
        android:id="@+id/child_detail"
        android:layout_width="wrap_content"
        android:layout_height="@dimen/dp_34_y"
        android:text="杀青"
        android:gravity="center"
        android:layout_marginLeft="@dimen/dp_12_x"
        />
</LinearLayout>

这点代码还是非常简单的,完全具备暴力美学

java代码

Activtiy.java

    @BindView(R.id.source_company_list)
    ExpandableListView company_list;
    @BindView(R.id.source_more)
    TextView company_more;

    Public void showResult(Company company){
     companyListAdapter = new CompanyListAdapter(this,sourceDataBean);
        company_list.setAdapter(companyListAdapter);
        params = ListViewParamsUtils.setListViewHeightBasedOnChildren(company_list);
        for (int i = 0; i < sourceDataBean.getProcessing_company().getDate_lists().size(); i++) {
            company_list.expandGroup(i);
        }

        company_list.setGroupIndicator(null);//取消箭头//设置父节点(章目录)不可点击
        //设置展开不关闭
        company_list.setOnGroupClickListener(new ExpandableListView.OnGroupClickListener() {
            @Override
            public boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long id) {
                return true;//返回true,表示不可点击
            }
        });

        params.height = params.height/4;//只显示1/4,当点击更多时显示全部
        company_list.setLayoutParams(params);
        company_more.setOnClickListener(this);
    }

东西太多?别急,我们慢慢来梳理一下。
首先,传入的参数company到底有什么?
这里写图片描述
分析这里面的结构,我创建了一个Company类
Company.java

@Data
public class Company {

    private List<Dates> date_list = new ArrayList<>();

    @Data
    public static class Dates{
        private String date;
        private List<Times> time_list = new ArrayList<>();
        @Data
        public static class Times{
            private String time;
            private String detail;
        }
    }
}

所以之前传进来的company就是网络请求后获取到的数据
接下来就是适配器的设计了
CompanyListAdapter.java

public class CompanyListAdapter extends BaseExpandableListAdapter {

//    private int mExpandedLayout;
    private int groupLayout;
    private int[] groups;

    private int childLayout;
    private int[] childs;

    private Company sourceDataBean;
    private String[] date;
    private data[] datas;
    private LayoutInflater mInflater;

    private Map<String,data[]> map = new HashMap<>();

    public void setReuslt(){
        date = new String[sourceDataBean.getDate_list().size()];
        for (int i=0;i<sourceDataBean.getDate_list().size();i++){
            date[i] = sourceDataBean.getDate_list().get(i).getDate();
            datas = new data[sourceDataBean.getDate_list().get(i).getTime_list().size()];
            for (int j = 0;j<sourceDataBean.getDate_list().get(i).getTime_list().size();j++){
                datas[j] = new data(sourceDataBean.getDate_list().get(i).getTime_list().get(j).getTime(),sourceDataBean.getDate_list().get(i).getTime_list().get(j).getDetail());

            }
            map.put(date[i],datas);
        }
    }


    public CompanyListAdapter(Context context, Company sourceDataBean){
        this.sourceDataBean =sourceDataBean;
        groupLayout = R.layout.group_date;
        groups = new int[]{R.id.gruop_date};
        childLayout = R.layout.child_detail;
        childs = new int[]{R.id.child_time,R.id.child_detail};
        mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        setReuslt();

    }

    @Override
    public int getGroupCount() {
        return date.length;
    }

    @Override
    public int getChildrenCount(int i) {

        return map.get(date[i]).length;
    }

    @Override
    public Object getGroup(int i) {

        return date[i];
    }

    @Override
    public Object getChild(int i, int i1) {
        return map.get(date[i])[i1];
    }

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

    @Override
    public long getChildId(int i, int i1) {
        return i1;
    }

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

    @Override
    public View getGroupView(int i, boolean b, View view, ViewGroup viewGroup) {
        View v;
        if (view==null){
            v= newGroupView(b,viewGroup);
        }else {
            v = view;
        }
        bindGroupView(v,date,i);
        return v;
    }

    private void bindGroupView(View v, String[] date,int i) {
        int len = date.length;
        TextView textView = v.findViewById(R.id.gruop_date);
        textView.setText(date[i]);
    }

    private View newGroupView(boolean b, ViewGroup viewGroup) {
        return mInflater.inflate(groupLayout,viewGroup,false);
    }

    @Override
    public View getChildView(int i, int i1, boolean b, View view, ViewGroup viewGroup) {
        View v;
        if (view == null){
            v= newChildView(b,viewGroup);
        }else {
            v = view;
        }

        bindChildView(v,map.get(date[i])[i1]);
        return v;
    }

    private void bindChildView(View v, data data) {
        TextView textView = v.findViewById(R.id.child_time);
        TextView textView1 = v.findViewById(R.id.child_detail);
        textView.setText(data.getTime());
        textView1.setText(data.getAction());
    }

    private View newChildView(boolean b, ViewGroup viewGroup) {
        return mInflater.inflate(childLayout,viewGroup,false);
    }

    /**
     * 指定子视图是否可选择
     * @param i
     * @param i1
     * @return
     */
    @Override
    public boolean isChildSelectable(int i, int i1) {
        return true;
    }
    @Data
    class data{
        private String time;
        private String action;
        public data(String time ,String action){
            this.time = time;
            this.action = action;
        }
    }
}

代码有点长了,这里解释一下,设计思路是

  • 将数据传进来适配器
  • getGroupView 方法中返回group_date视图,并写入相应数据
  • getChildVierw 方法中返回child_detail视图,并写入相应数据
  • 这里代码看起来虽然多,但关键只需要理解newGroupView和BindGroupView方法里面的代码

这里就完成了基本的代码完成了

出现的一些问题

显示只显示一行或者完全不显示,这里可以通过去测量它本身的大小去自定义显示容器的大小
建立工具类
ListViewParamsUtils.java

    public static ViewGroup.LayoutParams  setListViewHeightBasedOnChildren(ExpandableListView listView){

        ExpandableListAdapter listAdapter = listView.getExpandableListAdapter();
        if (listAdapter == null) {
            return null;
        }
        //初始化高度
        int totalHeight = 0;
        //分割线数量
        int count = 0;
        for (int i = 0; i < listAdapter.getGroupCount(); i++) {
            View listItem = listAdapter.getGroupView(i,true,null,listView);
            //计算子项View的宽高,注意listview所在的要是linearlayout布局
            listItem.measure(0, 0);
            //统计所有子项的总高度
            totalHeight += listItem.getMeasuredHeight();
            count++;
            for (int j = 0; j < listAdapter.getChildrenCount(i); j++) {
                View childItem = listAdapter.getChildView(i,j,true,null,listView);
                childItem.measure(0,0);
                totalHeight += childItem.getMeasuredHeight();
                count++;
            }

        }

        ViewGroup.LayoutParams params = listView.getLayoutParams();

        /*
         * listView.getDividerHeight()获取子项间分隔符占用的高度,有多少项就乘以多少个减一
         * params.height最后得到整个ListView完整显示需要的高度
         * 最后将params.height设置为listview的高度
         */

        params.height = totalHeight + (listView.getDividerHeight() * (count - 1));
        return params;
    }

然后在activity调用方法

    ViewGroup.LayoutParams params = ListViewParamsUtils.setListViewHeightBasedOnChildren(company_list);
    company_list.setLayoutParams(params);
扩展小功能

有时候获取的数据过多,并不想让它占的视图过大。我们可以通过获取到的params设置大小,当想看全部信息时展开,如下图
这里写图片描述
监听实现方法

private void showCompanyAll() {
        if (companyAll){
            params.height = params.height/4;//只显示1/4,当点击更多时显示全部
            company_list.setLayoutParams(params);
            companyAll = false;
            company_more.setText("查看更多");
        }else {
            params.height = params.height*4;//显示全部,当点击更多时显示全部
            company_list.setLayoutParams(params);
            companyAll = true;
            company_more.setText("收回");
        }
    }

有趣的东西太多,人生太短,抓紧时间,努力学习

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ExpandableListView实例(一)_数据库增删改查处理和listitem点击长按处理 本例说明: 1.实例中表现层与数据处理层分开,代码可复用性强,如果能看懂代码对算法会有提高. 2.组和子条目上"点击"事件处理,能够区分操作的是组还是子条目,并且得到组和子条目的内容. 3.组和子条目上"长按"事件处理,能够区分组和子条目,并且得到组和子条目的内容. 4.自定义条目样式,灵活与数据库中字段绑定. 5.实现对DB的增删改查,并且操作后自动刷新. 6.使用数据库处理框架AHibernate灵活操作sqlite数据库,详见: http://blog.csdn.net/lk_blog/article/details/7455992 ExpandableListView实例(二)_两种方式实现QQ中组后面显示子条目数量效果 本例说明: QQ,飞信等聊天工具中组后面后会显示有多少个子条目,这个是如何实现的呢?查阅了网上还没有相关的介绍,现在本文介绍两种方式实现此功能. 第一种方式:自定义Adapter,重写getGroupView方法. 第二种方式:自定义group.xml中的控件,加一个textview用于显示子条目个数. 注:本文数据库处理使用框架AHibernate,可以灵活操作sqlite数据库, 详见: http://blog.csdn.net/lk_blog/article/details/7455992 ExpandableListView实例(三)_实现QQ中"未分组"效果和"未分组"不可编辑删除功能 本例说明: 实现QQ中"未分组"效果和"未分组"不可编辑删除功能. 注:本文数据库处理使用框架AHibernate,可以灵活操作sqlite数据库, 详见: http://blog.csdn.net/lk_blog/article/details/7455992
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值