使用expandableListView实现三级列表

        时间过得很快,转眼年也过完了,在匆匆的岁月长河里总是莫名的心慌,可能时间真的是最残忍的那个,无论你喜或悲、乐与乏,他都持续流逝着,不快不慢。废话不多说,在开工的前一天(昨天)陈闲暇之时写了一个通过expandableListView实现三级列表的demo,昨天写完demo就没时间了,今天写到博客里,算是新年开工第一篇了。

首先看一下效果图:


我们都知道,通过expandableListView可以实现两级列表,那么怎么实现三级列表呢?其实也简单,我们可以通过expandableListView嵌套expandableListView的方式实现。

ExpendableListView的使用和ListView几乎一样:

  • 编写布局文件并获取ExpendableListView
  • 自定义适配器继承BaseExpandableListAdapter。
  • setAdapter设置适配器。

下面开始进行实现:

  • 编写布局文件并查找控件
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 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"
    tools:context="com.example.cui.therelisttestdemo.MainActivity">

    <ExpandableListView
        android:id="@+id/expandable_listView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="Hello World!"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</android.support.constraint.ConstraintLayout>
  • 自定义Adapter继承自BaseExpandableListAdapter,此处因为使用的实expandableListView的嵌套,所以也需要定义两个adapter,我们分别称之为OuterAdapter和InnerAdapter。

在编写该类之前,我们必须要有我们的实体类。看一下我们定义的国家、省、市实体类Classes,并分别设置他的set和get方法。

 

/**
 * 国家实体类
 * Created by Administrator on 2018/2/21.
 */

public class CountyEntity {
    //国家名
    private String name;
    //国家的省集合
    private List<Province> provinces;

    public String getName() {
        return name;
    }

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

    public List<Province> getProvinces() {
        return provinces;
    }

    public void setProvinces(List<Province> provinces) {
        this.provinces = provinces;
    }


    /**
     * 省实体类
     */
    static class Province{
        //省的名称
        private String name;

        //省内的城市集合
        private List<City> cities;

        public String getName() {
            return name;
        }

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

        public List<City> getCities() {
            return cities;
        }

        public void setCities(List<City> cities) {
            this.cities = cities;
        }
    }


    /**
     * 城市实体类
     */
    static class City{
        //城市名称
        private String name;

        public String getName() {
            return name;
        }

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

ok,写完实体类后直接上OuterAdapter和InnerAdapter的代码。

OuterAdaper:

public class OutAdapter extends BaseExpandableListAdapter {
    private List<CountyEntity> countyEntities;//国家的集合
    private Activity activity;//创建布局使用
    //构造方法
    public OutAdapter(List<CountyEntity> countyEntities, Activity activity) {
        if (countyEntities != null) {
            this.countyEntities = countyEntities;
        } else countyEntities = new ArrayList<>();
        this.activity = activity;
    }
    // 组数量
    @Override
    public int getGroupCount() {
        return countyEntities.size();
    }
    //子View数量
    @Override
    public int getChildrenCount(int i) {
        return 1;
    }
    //获取组对象
    @Override
    public Object getGroup(int i) {
        return countyEntities.get(i);
    }
    //获取子View对象
    @Override
    public Object getChild(int i, int i1) {
        return countyEntities.get(i).getProvinces().get(i1);
    }
    // 组View下标
    @Override
    public long getGroupId(int i) {
        return i;
    }
    //子View下标
    @Override
    public long getChildId(int i, int i1) {
        return i1;
    }

    @Override
    public boolean hasStableIds() {
        return false;
    }
    //获取组布局
    @Override
    public View getGroupView(int i, boolean b, View view, ViewGroup viewGroup) {
        TextView textView = new TextView(activity);
        AbsListView.LayoutParams params = new AbsListView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        textView.setLayoutParams(params);
        textView.setLeft(20);
        textView.setPadding(90, 15, 10, 15);
        textView.setGravity(Gravity.CENTER_VERTICAL | Gravity.LEFT);
        textView.setText(countyEntities.get(i).getName());
        return textView;
    }
    //获取子View
    @Override
    public View getChildView(int i, int i1, boolean b, View view, ViewGroup viewGroup) {
        AbsListView.LayoutParams params = new AbsListView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        InnerExpandableListView expandableListView = new InnerExpandableListView(activity);
        expandableListView.setLayoutParams(params);
        InnerAdapter adapter = new InnerAdapter(countyEntities.get(i).getProvinces(), activity);
        expandableListView.setAdapter(adapter);
        expandableListView.setPadding(90, 15, 5, 15);
        return expandableListView;
    }
    @Override
    public boolean isChildSelectable(int i, int i1) {
        return true;
    }
}

InerAdapter:

public class InnerAdapter extends BaseExpandableListAdapter {
    private List<CountyEntity.Province> provinces;.//省的集合
    private Activity activity;//创建布局使用
    //构造参数
    public InnerAdapter(List<CountyEntity.Province> provinces, Activity activity) {
        if (provinces!=null) {
            this.provinces = provinces;
        }else provinces=new ArrayList<>();
        this.activity = activity;
    }
    //获取外层组个数
    @Override
    public int getGroupCount() {
        return provinces.size();
    }
    //获取内层组个数
    @Override
    public int getChildrenCount(int i) {
        return provinces.get(i).getCities().size();
    }
    //获取外层组
    @Override
    public Object getGroup(int i) {
        return provinces.get(i);
    }
    //获取内层数据
    @Override
    public Object getChild(int i, int i1) {
        return provinces.get(i).getCities().get(i1);
    }
    //组下标
    @Override
    public long getGroupId(int i) {
        return i;
    }
    //子View下标
    @Override
    public long getChildId(int i, int i1) {
        return i1;
    }
    //不知道做什么用
    @Override
    public boolean hasStableIds() {
        return false;
    }
    //获取组布局
    @Override
    public View getGroupView(int i, boolean b, View view, ViewGroup viewGroup) {
        TextView textView=new TextView(activity);
        AbsListView.LayoutParams params=new AbsListView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        textView.setLayoutParams(params);
        textView.setPadding(90,15,10,15);
        textView.setGravity(Gravity.CENTER_VERTICAL|Gravity.LEFT);
        textView.setText(provinces.get(i).getName());
        return textView;
    }
    //获取子View布局
    @Override
    public View getChildView(int i, int i1, boolean b, View view, ViewGroup viewGroup) {
        TextView textView=new TextView(activity);
        AbsListView.LayoutParams params=new AbsListView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        textView.setLayoutParams(params);
        textView.setPadding(110,15,10,15);
        textView.setGravity(Gravity.CENTER_VERTICAL|Gravity.LEFT);
        textView.setText(provinces.get(i).getCities().get(i1).getName());
        return textView;
    }
    //子View是否可选
    @Override
    public boolean isChildSelectable(int i, int i1) {
        return true;
    }
}

观察可以发现,OuterAdapter和InnerAdapter的代码几乎全部相同,其中之一的不同是返回的子View不同,在OuterAdapter中子View返回的是我们自定义的一个InnerExpandableListView继承自expandableListView(这里之所以要自定义expandableListView是因为在ListView嵌套ListView的时候发现里边的ListView显示不全,为了全部显示,重写了expandableListView),这就是我们说的expandableListView嵌套expandableListView,通过adapter类返回一个expandableListView实现。还有一个不同那就是在OuterAdapter返回子View个数的时候我们返回的是1,记住,这个 非常关键,因为他具体的显示都交给了子ExpandableListView,二级条目的目的是为了把子ExpandableListView显示出来

下面简单介绍其中几个关键方法

  • getGroupCount():获取一级条目的数量。
  • getChildrenCount():获取二级条目的数量。
  • getGroupView():获取一级条目的对应布局。
  • getChildView():获取二级条目对应的布局。

  • 再看一下InnerExpandableListView的写法

public class InnerExpandableListView extends ExpandableListView {
    public InnerExpandableListView(Context context) {
        super(context);
    }

    public InnerExpandableListView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public InnerExpandableListView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }
    //通过此方法重新计算expandableListView的高度,使得里边的expandableListView全部显示
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2
                , MeasureSpec.AT_MOST);
        super.onMeasure(widthMeasureSpec, expandSpec);
    }
}
  • setAdapter()设置适配器

public class MainActivity extends AppCompatActivity {
    private ExpandableListView expandableListView;
    List<CountyEntity> countyEntities=new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        expandableListView = findViewById(R.id.expandable_listView);
        initData();
        //创建适配器实例,设置适配器
        OutAdapter adapter=new OutAdapter(countyEntities,this);
        expandableListView.setAdapter(adapter);
    }
    //创造数据
    private void initData() {

        for (int m=0;m<4;m++) {
            CountyEntity countyEntity=new CountyEntity();
            countyEntity.setName("国家"+m);
            List<CountyEntity.Province> provinces=new ArrayList<>();
            for (int j = 0; j < 6; j++) {
                CountyEntity.Province province=new CountyEntity.Province();
                province.setName("省"+j);
                List<CountyEntity.City> cities = new ArrayList<>();
                for (int i = 0; i < 5; i++) {
                    CountyEntity.City city = new CountyEntity.City();
                    city.setName("城市" + i);
                    cities.add(city);
                }
                province.setCities(cities);
                provinces.add(province);
            }
            countyEntity.setProvinces(provinces);
            countyEntities.add(countyEntity);
        }
    }
}

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用ExpandableListView可以实现QQ好友分组列表。首先需要创建一个ExpandableListView控件,并为其设置适配器。适配器需要继承BaseExpandableListAdapter,并实现以下方法: 1. getGroupCount():获取分组的数量。 2. getChildrenCount():获取某个分组下子项的数量。 3. getGroup():获取某个分组的数据。 4. getChild():获取某个分组下某个子项的数据。 5. getGroupId():获取某个分组的ID。 6. getChildId():获取某个分组下某个子项的ID。 7. hasStableIds():判断分组和子项的ID是否稳定。 8. getGroupView():获取分组的视图。 9. getChildView():获取子项的视图。 10. isChildSelectable():判断子项是否可选中。 在实现适配器的过程中,需要根据数据源的结构来设置分组和子项的数据。例如,可以使用一个List<List<String>>来存储分组和子项的数据,其中外层List表示分组,内层List表示子项。在getGroup()和getChild()方法中,需要根据groupPosition和childPosition来获取对应的数据。 最后,需要为ExpandableListView设置分组的展开和收起事件。可以通过设置OnGroupClickListener和OnChildClickListener来实现。在OnGroupClickListener中,需要根据groupPosition来判断当前分组是否已经展开,如果已经展开则返回false,否则返回true。在OnChildClickListener中,可以根据childPosition来获取对应的数据,并进行相应的操作。 通过以上步骤,就可以实现一个简单的QQ好友分组列表

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值