Android 二级列表控件ExpandableListView 的简单使用

本文介绍了如何在Android中使用ExpandableListView并自定义适配器FoodinfoExpandableAdapter,通过扩展BaseExpandableListAdapter来处理分组和子项的数据。示例代码展示了如何设置布局、取消默认箭头、绑定数据以及处理视图的创建和复用。同时强调了在getGroupView方法中避免设置抢占焦点的属性,以确保子列表能正常展开。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

先上图:

页面布局

布局很简单,就一个ExpandableListView ,直接上布局截图,相信各位能看懂

 由于其控件会默认自带箭头,我们可以通过XML中在ExpandableListView控件加上

     android:groupIndicator="@null"

取消掉其自带的指示器箭头,当然除了在xml上,也可通过在代码中,当绑定完控件后调用代码也可实现取消效果

 expandableListView.setGroupIndicator(null);

接下来是我们重点要研究的适配器FoodinfoExpandableAdapter,继承并重写了BaseExpandableListAdapter这个类的相关函数,其中注释我已经详细写在代码中,若是不懂或者写错,希望各位可以交流或指出,大家一起加深对其认识。

public class FoodinfoExpandableAdapter extends BaseExpandableListAdapter {

    private final Context context;
    private List<Foodinfo> data;

    public FoodinfoExpandableAdapter(Context context, List<Foodinfo> data) {
        this.context = context;
        this.data = data;
    }

    /**
     * 获取组的数目
     *
     * @return 返回一级列表组的数量
     */
    @Override
    public int getGroupCount() {
        return data == null ? 0 : data.size();
    }

    /**
     * 获取指定组中的子节点数量
     *
     * @param groupPosition 子元素组所在的位置
     * @return 返回指定组中的子数量
     */
    @Override
    public int getChildrenCount(int groupPosition) {
        return data.get(groupPosition).getFoodinfoChildrenList().size();
    }

    /**
     * 获取与给定组相关联的对象
     *
     * @param groupPosition 子元素组所在的位置
     * @return 返回指定组的子数据
     */
    @Override
    public Object getGroup(int groupPosition) {
        return data.get(groupPosition).getFoodType();
    }


    /**
     * 获取与给定组中的给定子元素关联的数据
     *
     * @param groupPosition 子元素组所在的位置
     * @param childPosition 子元素的位置
     * @return 返回子元素的对象
     */
    @Override
    public Object getChild(int groupPosition, int childPosition) {
        return data.get(groupPosition).getFoodinfoChildrenList().get(childPosition);
    }

    /**
     * 获取组在给定位置的ID(唯一的)
     *
     * @param groupPosition 子元素组所在的位置
     * @return 返回关联组ID
     */
    @Override
    public long getGroupId(int groupPosition) {
        return groupPosition;
    }


    /**
     * 获取给定组中给定子元素的ID(唯一的)
     *
     * @param groupPosition 子元素组所在的位置
     * @param childPosition 子元素的位置
     * @return 返回子元素关联的ID
     */
    @Override
    public long getChildId(int groupPosition, int childPosition) {
        return childPosition;
    }

    /**
     * @return 确定id 是否总是指向同一个对象
     */
    @Override
    public boolean hasStableIds() {
        return true;
    }

    /**
     * @return 返回指定组的对应的视图 (一级列表样式)
     */
    @Override
    public View getGroupView(final int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
        ParentHolder parentHolder;
        if (convertView == null) {
            convertView = LayoutInflater.from(context).inflate(R.layout.level_item, null);
            parentHolder = new ParentHolder();
            parentHolder.tvParent = convertView.findViewById(R.id.tv_parent);
            parentHolder.img_left = convertView.findViewById(R.id.img_left);
            parentHolder.img_right = convertView.findViewById(R.id.img_right);
            convertView.setTag(parentHolder);
        } else {
            parentHolder = (ParentHolder) convertView.getTag();
        }
        parentHolder.tvParent.setText(data.get(groupPosition).getFoodType());
        parentHolder.img_left.setImageResource(data.get(groupPosition).getFoodTypeImg());


        //共用一个右箭头,如果展开则顺时针旋转90°选择,否则不旋转
        if (isExpanded) parentHolder.img_right.setRotation(90F);
        else parentHolder.img_right.setRotation(0F);

        return convertView;
    }

    /**
     * @return 返回指定位置对应子视图的视图
     */
    @Override
    public View getChildView(final int groupPosition, final int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
        final ChildrenHolder childrenHolder;
        if (convertView == null) {
            convertView = LayoutInflater.from(context).inflate(R.layout.level2_item, null);
            childrenHolder = new ChildrenHolder();
            childrenHolder.tvChild = convertView.findViewById(R.id.tv_child);
            childrenHolder.imageView = convertView.findViewById(R.id.child_img);
            convertView.setTag(childrenHolder);
        } else {
            childrenHolder = (ChildrenHolder) convertView.getTag();
        }


        childrenHolder.tvChild.setText(data.get(groupPosition).getFoodinfoChildrenList().get(childPosition).getName());
        childrenHolder.imageView.setImageResource(data.get(groupPosition).getFoodinfoChildrenList().get(childPosition).getFoodinfoChildrenImg());

        return convertView;
    }

    /**
     * 指定位置的子元素是否可选
     *
     * @param groupPosition 子元素组所在的位置
     * @param childPosition 子元素的位置
     * @return 返回是否可选
     */

    @Override
    public boolean isChildSelectable(int groupPosition, int childPosition) {
        return true;
    }


    class ParentHolder {
        TextView tvParent;
        ImageView img_left, img_right;
    }


    class ChildrenHolder {
        TextView tvChild;
        ImageView imageView;
    }

}

父布局使用的xml:

子布局使用的xml:

注意在getGroupView中getGroupView的控件不能设置一些抢占焦点的事件或属性,如点击事件或者在代码布局里设置了focusable属性为true,都会导致无法展开子列表。

实体类Foodinfo代码如下:

public class Foodinfo {
    private String foodType;
    private int foodTypeImg;
    private List<FoodinfoChildren> foodinfoChildrenList;

    public Foodinfo(String foodType, int foodTypeImg, List<FoodinfoChildren> foodinfoChildrenList) {
        this.foodType = foodType;
        this.foodTypeImg = foodTypeImg;
        this.foodinfoChildrenList = foodinfoChildrenList;
    }

    public String getFoodType() {
        return foodType;
    }

    public void setFoodType(String foodType) {
        this.foodType = foodType;
    }

    public int getFoodTypeImg() {
        return foodTypeImg;
    }

    public void setFoodTypeImg(int foodTypeImg) {
        this.foodTypeImg = foodTypeImg;
    }

    public List<FoodinfoChildren> getFoodinfoChildrenList() {
        return foodinfoChildrenList;
    }

    public void setFoodinfoChildrenList(List<FoodinfoChildren> foodinfoChildrenList) {
        this.foodinfoChildrenList = foodinfoChildrenList;
    }
}

最后是在我们的主界面中实现代码

public class Food_information_Activity extends AppCompatActivity {

    private static List<Foodinfo> foodinfoList;
    private static FoodinfoExpandableAdapter foodinfoExpandableAdapter;
    private ExpandableListView listView;

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

        TextView title = findViewById(R.id.title_layout);
        title.setText("食物分类");
        listView = findViewById(R.id.food_info_list);

        initData();
        initAdapter();

    }

    private final String[] foodTypes = {"鱼肉海鲜", "肉类", "蔬菜豆类", "水果"};
    private final int[] foodTypeImg = {R.drawable.type1, R.drawable.type2, R.drawable.type3, R.drawable.type4};

    private final String[] yl = {"草鱼", "鲤鱼", "鲫鱼", "鱿鱼"};
    private final int[] ylImg = {R.drawable.yl1, R.drawable.yl2, R.drawable.yl3, R.drawable.yl4};

    private final String[] rl = {"牛肉", "猪肉", "羊肉", "鸡肉"};
    private final int[] rlImg = {R.drawable.rl1, R.drawable.rl2, R.drawable.rl3, R.drawable.rl4};

    private final String[] sd = {"豌豆", "胡萝卜", "生菜", "空心菜"};
    private final int[] sdImg = {R.drawable.sd1, R.drawable.sd2, R.drawable.sd3, R.drawable.sd4};

    private final String[] sg = {"橘子", "哈密瓜", "苹果", "黄桃"};
    private final int[] sgImg = {R.drawable.sg1, R.drawable.sg2, R.drawable.sg3, R.drawable.sg4};

    private void initData() {
        foodinfoList = new ArrayList<>();

        List<FoodinfoChildren> ylFood = new ArrayList<>();
        for (int j = 0; j < 4; j++) {
            ylFood.add(new FoodinfoChildren(yl[j], ylImg[j]));
        }

        List<FoodinfoChildren> rlFood = new ArrayList<>();
        for (int j = 0; j < 4; j++) {
            rlFood.add(new FoodinfoChildren(rl[j], rlImg[j]));
        }

        List<FoodinfoChildren> sdFood = new ArrayList<>();
        for (int j = 0; j < 4; j++) {
            sdFood.add(new FoodinfoChildren(sd[j], sdImg[j]));
        }

        List<FoodinfoChildren> sgFood = new ArrayList<>();
        for (int j = 0; j < 4; j++) {
            sgFood.add(new FoodinfoChildren(sg[j], sgImg[j]));
        }

        foodinfoList.add(new Foodinfo(foodTypes[0], foodTypeImg[0], ylFood));
        foodinfoList.add(new Foodinfo(foodTypes[1], foodTypeImg[1], rlFood));
        foodinfoList.add(new Foodinfo(foodTypes[2], foodTypeImg[2], sdFood));
        foodinfoList.add(new Foodinfo(foodTypes[3], foodTypeImg[3], sgFood));

    }

    private void initAdapter() {
        foodinfoExpandableAdapter = new FoodinfoExpandableAdapter(this, foodinfoList);
        listView.setAdapter(foodinfoExpandableAdapter);

        /**
         * 默认展开某个item
         * */
        //expandableListView.expandGroup(1);

    }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

.鱼子酱

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值