安卓ExpandableListView的详细使用教程(附代码解析过程)[通俗易懂]

安卓ExpandableListView的详细使用教程(附代码解析过程)[通俗易懂]ExpandableListView又称可扩展的ListView,它可以实现点击父项展开子项的效果,本文实现了一个比较精美的ExpandableListView。

大家好,又见面了,我是你们的朋友全栈君。

一、实现效果

  ExpandableListView又称可扩展的ListView,简单来说长这个样:
在这里插入图片描述
每一个一级布局下面又可以展开二级布局

二、实现步骤

使用ExpandableListView主要有三个步骤:

  1. 编写父布局
  2. 编写子布局
  3. 适配器的书写

1.编写父布局parent.xml

  父布局其实很简单,就是两个并排的TextView,用于展示课程名字和分数:

<?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:background="#F0F3F6" android:orientation="horizontal">

    <LinearLayout style="@style/bg_layout" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_margin="1dp" android:clickable="false">

        <TextView android:id="@+id/tv_course_name" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="4" android:gravity="center_vertical" android:paddingBottom="8dp" android:paddingLeft="30dp" android:paddingTop="8dp" android:text="课程名" android:textColor="#000" android:textSize="16sp" />

        <TextView android:id="@+id/tv_mark" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:gravity="center_vertical" android:paddingBottom="8dp" android:paddingTop="8dp" android:text="等级" android:textColor="#333" android:textSize="16sp" />
    </LinearLayout>
</LinearLayout>

2.编写子布局child.xml

  子布局就是多个TextView列在一起,用于展示成绩的详细信息:

<?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:background="#F0F0F0" android:orientation="vertical" android:padding="7dp">

    <TextView android:id="@+id/tv_xn" style="@style/item_child_grade" />

    <TextView android:id="@+id/tv_xq" style="@style/item_child_grade" />

    <TextView android:id="@+id/tv_course_code" style="@style/item_child_grade" />

    <TextView android:id="@+id/tv_course_nature" style="@style/item_child_grade" />


    <TextView android:id="@+id/tv_credit" style="@style/item_child_grade" />

    <TextView android:id="@+id/tv_gpa" style="@style/item_child_grade" />

    <TextView android:id="@+id/tv_college" style="@style/item_child_grade" />


    <TextView android:id="@+id/tv_class" style="@style/item_child_grade" />

    <TextView android:id="@+id/tv_teacher" style="@style/item_child_grade" />


</LinearLayout>

3.编写适配器类GradeAdapter

  一般适用于ExpandableListView的Adapter都要继承BaseExpandableListAdapter这个类,并且必须重载getGroupView和getChildView这两个最为重要的方法。

  1. getGroupView(),返回外面那层布局的视图,也就是各种课程的名称以及分数:在这里插入图片描述

  2. getChildView(),返回子布局里面的视图,也就是每门学科的详细信息:在这里插入图片描述

GradeAdapter的详细代码为:

package com.example.edm.adapter;

import android.content.Context;
import androidx.cardview.widget.CardView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.BaseExpandableListAdapter;
import android.widget.ListView;
import android.widget.TextView;

import com.example.edm.R;
import com.example.edm.Student.Grade;

import java.util.List;


public class GradeAdapter extends BaseExpandableListAdapter { 
   
    private Context context;
    private List<Grade> list;

    public GradeAdapter(Context context, List<Grade> list) { 
   
        this.context = context;
        this.list = list;

    }


    @Override
    //获取分组个数
    public int getGroupCount() { 
   
        return list.size();
    }

    @Override
    //分组中子选项个数为1
    public int getChildrenCount(int i) { 
   
        return 1;
    }

    @Override
    //获取指定分组数据
    public Object getGroup(int i) { 
   
        return list.get(i);
    }

    @Override
    //获取指定子选项数据
    public Object getChild(int i, int j) { 
   
        return null;
    }

    @Override
    //获取指定分组的id
    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 convertView, ViewGroup viewGroup) { 
   
        View view;
        GroupHolder groupHolder;
        if (convertView == null) { 
   
            //父布局
            view = View.inflate(context, R.layout.parent, null);
            groupHolder = new GroupHolder();
            groupHolder.tv_course_name = view.findViewById(R.id.tv_course_name); //课程名
            groupHolder.tv_mark = view.findViewById(R.id.tv_mark);   //成绩
            view.setTag(groupHolder);
        } else { 
   
            view = convertView;
            groupHolder = (GroupHolder) view.getTag();
        }
        groupHolder.tv_course_name.setText(list.get(i).getCourse_name());
        groupHolder.tv_mark.setText(list.get(i).getMark());
        return view;
    }

    public View getChildView(int i, int i1, boolean b, View convertView, ViewGroup viewGroup) { 
   
        View view;
        ChildHolder childHolder;
        if (convertView == null) { 
   
            view = View.inflate(context, R.layout.child, null);
            childHolder = new ChildHolder();
            childHolder.tv_xn = view.findViewById(R.id.tv_xn);
            childHolder.tv_xq =  view.findViewById(R.id.tv_xq);
            childHolder.tv_course_code =  view.findViewById(R.id.tv_course_code);
            childHolder.tv_course_nature =  view.findViewById(R.id.tv_course_nature);
            childHolder.tv_credit =  view.findViewById(R.id.tv_credit);
            childHolder.tv_gpa =  view.findViewById(R.id.tv_gpa);;
            childHolder.tv_college = view.findViewById(R.id.tv_college);
            childHolder.tv_class = view.findViewById(R.id.tv_class);
            childHolder.tv_teacher = view.findViewById(R.id.tv_teacher);

            view.setTag(childHolder);

        } else { 
   
            view = convertView;
            childHolder = (ChildHolder) view.getTag();
        }
        childHolder.tv_xn.setText("学年:" + list.get(i).getXn());
        childHolder.tv_xq.setText("学期:" + list.get(i).getXq());
        childHolder.tv_course_code.setText("课程代码:" + list.get(i).getCourse_code());
        childHolder.tv_course_nature.setText("课程性质:" + list.get(i).getCourse_nature());
        childHolder.tv_credit.setText("学分:" + list.get(i).getCredit());
        childHolder.tv_gpa.setText("绩点:" + list.get(i).getGpa());
        childHolder.tv_college.setText("开课学院:" + list.get(i).getCollege());
        childHolder.tv_class.setText("教学班:" + list.get(i).getClass_());
        childHolder.tv_teacher.setText("任课教师:" + list.get(i).getTeacher());

        return view;
    }

    @Override
    public boolean isChildSelectable(int i, int i1) { 
   
        return false;
    }

    static class GroupHolder { 
   
        TextView tv_course_name;
        TextView tv_mark;
    }

    static class ChildHolder { 
   
        TextView tv_xn;
        TextView tv_xq;
        TextView tv_course_code;
        TextView tv_course_nature;
        TextView tv_credit;
        TextView tv_gpa;
        TextView tv_college;
        TextView tv_class;
        TextView tv_teacher;
    }
}

三、解析适配器类

  适配器类有一个私有列表变量,列表的类型为Grade,Grade是一个封装好的关于成绩信息的类,Grade.java代码为:

package com.example.edm.Student;

public class Grade { 
   
    private String xn;   //学年
    private String xq;    //学期
    private String course_code;   //课程代码
    private String course_name;   //课程名字
    private String course_nature;  //课程性质
    private String credit;   //学分
    private String gpa;   //绩点
    private String mark;    //分数
    private String grade_nature;  //成绩性质
    private String class_;  //教学班
    private String teacher; //老师

    public String getXn() { 
   
        return xn;
    }

    public void setXn(String xn) { 
   
        this.xn = xn;
    }

    public String getXq() { 
   
        return xq;
    }

    public void setXq(String xq) { 
   
        this.xq = xq;
    }

    public String getCourse_code() { 
   
        return course_code;
    }

    public void setCourse_code(String course_code) { 
   
        this.course_code = course_code;
    }

    public String getCourse_name() { 
   
        return course_name;
    }

    public void setCourse_name(String course_name) { 
   
        this.course_name = course_name;
    }

    public String getCourse_nature() { 
   
        return course_nature;
    }

    public void setCourse_nature(String course_nature) { 
   
        this.course_nature = course_nature;
    }

    public String getCredit() { 
   
        return credit;
    }

    public void setCredit(String credit) { 
   
        this.credit = credit;
    }

    public String getGpa() { 
   
        return gpa;
    }

    public void setGpa(String gpa) { 
   
        this.gpa = gpa;
    }

    public String getMark() { 
   
        return mark;
    }

    public void setMark(String mark) { 
   
        this.mark = mark;
    }
    
    public String getCollege() { 
   
        return college;
    }

    public void setCollege(String college) { 
   
        this.college = college;
    }

    public String getClass_() { 
    return class_; }

    public void setClass_(String class_) { 
   
        this.class_ = class_;
    }

    public String getTeacher() { 
    return teacher; }

    public void setTeacher(String teacher) { 
   
        this.teacher = teacher;
    }
}

里面包含设置和获取每种信息的方法。

  getGroupView和getChildView两个方法我举getGroupView来详细讲解:

public View getGroupView(int i, boolean b, View convertView, ViewGroup viewGroup) { 
   
        View view;
        GroupHolder groupHolder;
        if (convertView == null) { 
   
            //父布局
            view = View.inflate(context, R.layout.parente, null);
            groupHolder = new GroupHolder();
            groupHolder.tv_course_name = view.findViewById(R.id.tv_course_name); //课程名
            groupHolder.tv_mark = view.findViewById(R.id.tv_mark);   //成绩
            view.setTag(groupHolder);
        } else { 
   
            view = convertView;
            groupHolder = (GroupHolder) view.getTag();
        }
        groupHolder.tv_course_name.setText(list.get(i).getCourse_name());
        groupHolder.tv_mark.setText(list.get(i).getMark());
        return view;
 }
view = View.inflate(context, R.layout.parent, null);

这句代码作用为设置外面布局为我们编写的parent.xml, 但现在里面还没有数据。
  我们定义了一个GroupHolder来保存这些数据:

static class GroupHolder { 
   
     TextView tv_course_name;
     TextView tv_mark;
}

里面包含了父布局的所有数据属性,我们在getGroupView中初始化这些变量,这些变量的数据都保存在list里面,都在我们初始化GradeAdapter时传进来。

groupHolder = new GroupHolder();
groupHolder.tv_course_name = view.findViewById(R.id.tv_course_name); //课程名
groupHolder.tv_mark = view.findViewById(R.id.tv_mark);   //成绩

设置groupHolder的各种值:

groupHolder.tv_course_name.setText(list.get(i).getCourse_name());
groupHolder.tv_mark.setText(list.get(i).getMark());

附上主界面GradeActivity代码:

String year = schoolYear.getText().toString();
String semester_ = semester.getText().toString();
String course_nature = course.getText().toString();
if(year.equals("学年")) { 
   
    ToastUtil.showMessage(this,"请选择学年!");
}else if(semester_.equals("学期")) { 
   
    ToastUtil.showMessage(this, "请选择学期!");
}else if(course_nature.equals("课程性质")) { 
   
    ToastUtil.showMessage(this, "请选择课程性质!");
}else { 
   
 //开始查询成绩并显示
    try { 
   
        String year_ = year.substring(0, 4);
        ArrayList<Grade> list = connectJWGL.getStudentGrade(Integer.parseInt(year_), Integer.parseInt(semester_), course_nature);
       if (list.size() == 0) { 
   
           ToastUtil.showMessage(this, "没有查到记录!");
       }else { 
   
           for(int i = 0; i < list.size(); ++i) { 
   
               list.get(i).setXn(year);
               list.get(i).setXq(semester_);
           }
           expand_lv.setAdapter(new GradeAdapter(this, list));
        }

     } catch (Exception e) { 
   
         e.printStackTrace();
     }
}

  这一步涉及到一些网络爬虫的知识,大家在用这个demo的时候只要自己定义一个list,然后在里面手动添加一些数据就好了。核心代码为:

expand_lv.setAdapter(new GradeAdapter(this, list));

list里面已经包含了所有我们需要的信息。
  布局代码也很简单,只要有一个ExpandableListView就好了:

 <ExpandableListView android:id="@+id/expand_lv" android:layout_margin="1dp" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#F0F3F6" android:divider="@null">
 </ExpandableListView>
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/147457.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • 云服务器搭建青龙面板每日自动拿京豆

    云服务器搭建青龙面板每日自动拿京豆前言:之前网上有只要扫码一下就可以每天领上百京豆和一些红包的活动,后来呢,扫码就失效了,但是呢,这背后的技术还没有失效。这白嫖活动其实就是用脚本代替我们去参与京东的各种活动,去获取红包和京豆,而这些脚本是部署在电脑上,定时去执行的,接下来,根据网上的大佬的教程,我们也来实现一下。每天100-200京豆不等,坐收渔利,快来试试吧。一、安装前的准备​青龙面板是使用Docker来安装的,理论上,只要有可以运行Docker的电脑都可以进行安装。但是呢,因为脚本要定时运行,所以最好安装在服务器上,或

    2022年10月14日
  • java引用变量存放在哪_java成员变量存储在哪个内存区域

    java引用变量存放在哪_java成员变量存储在哪个内存区域我们说常量,静态变量存放在方法区中,方法中的临时变量,存放到Java虚拟栈中。有人问,那全局变量*(对象)存放在哪里.其实全局变量就是参考文章中所说的class的字段,就是指全局变量,它是存放在方法区中的。e)方法区与堆一样,是被线程共享的区域。在方法区中,存储了每个类的信息(包括类的名称、方法信息、字段信息)、静态变量、常量以及编译器编译后的代码等。在Class文件中除了类的字段、方法、接…

  • Android——谷歌官方下拉刷新控件SwipeRefreshLayout「建议收藏」

    Android——谷歌官方下拉刷新控件SwipeRefreshLayout「建议收藏」转自:http://blog.csdn.net/zouzhigang96/article/details/50476402前言: 如今谷歌推出了更官方的下拉刷新控件,这无疑是对安卓开发人员来说是个好消息,很方便的使用这个SwipeRefreshLayout控件实现下拉刷新功能。Android4.0以下的版本需要用到android-support-v4.jar包才能用到 andr

  • 用Excel处理笛卡尔积

    用Excel处理笛卡尔积    工作中遇到需要处理笛卡尔积的需求,用数据库只需把需要做笛卡尔积的各列进行外链接就可以了,想到Excel应该可以处理这样的需求,就百度学习了一下,但还是看不太懂,下面只是依葫芦画瓢做了一遍,记录一下。1、构建两列数据,如下图:2、构建D列辅助列,E列为用index函数处理A列后的数据,每个值的重复次数为B列的数值行数。3、用index()函数处理B列:…

  • SqlSessionTemplate MapperScannerConfigurer「建议收藏」

    SqlSessionTemplate MapperScannerConfigurer「建议收藏」mybatis SqlSessionFactoryBean SqlSessionTemplateMapperScannerConfigurer1.MyBatis简介   MyBatis是什么?MyBatis是一款一流的支持自定义SQL、存储过程和高级映射的持久化框架。MyBatis几乎消除了所有的JDBC代码,也基本不需要手工去设置参数和获取检索结果。MyBatis能够使用简单的XM

  • Laravel之路由 Route::get/post/any、路由参数、过滤器、命名、子域名、前缀、与模型绑定、抛出 404 错误、控制器…

    Laravel之路由 Route::get/post/any、路由参数、过滤器、命名、子域名、前缀、与模型绑定、抛出 404 错误、控制器…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号