在旧版 Android 界面中使用 ExpandableListView

426 字
2 分钟
在旧版 Android 界面中使用 ExpandableListView

目标#

在需要维护传统 View 界面的项目中,用 ExpandableListView 展示省份与城市两级列表,不再继承已弃用的 ExpandableListActivity。

适用范围#

ExpandableListView 适合维护既有两级列表。新项目如果需要更灵活的交互、动画或多层数据,优先考虑 RecyclerView 或 Jetpack Compose 的可展开列表模式。

Android Studio 中 ExpandableListActivity 弃用提示
历史版本中的弃用提示;新代码不再继承 ExpandableListActivity。

添加布局#

<?xml version="1.0" encoding="utf-8"?>
<ExpandableListView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/expandable_list"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

准备数据和适配器#

private final String[] provinces = {
    "山西省", "吉林省", "河北省", "山东省"
};

private final String[][] cities = {
    {"太原市", "吕梁市", "长治市"},
    {"长春市", "松原市", "吉林市"},
    {"石家庄市", "唐山市", "承德市"},
    {"菏泽市", "青岛市", "济南市"}
};

核心适配器实现如下。示例复用 convertView,避免滚动时重复创建视图:

class RegionAdapter extends BaseExpandableListAdapter {
    @Override
    public int getGroupCount() {
        return provinces.length;
    }

    @Override
    public int getChildrenCount(int groupPosition) {
        return cities[groupPosition].length;
    }

    @Override
    public Object getGroup(int groupPosition) {
        return provinces[groupPosition];
    }

    @Override
    public Object getChild(int groupPosition, int childPosition) {
        return cities[groupPosition][childPosition];
    }

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

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

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

    @Override
    public View getGroupView(
        int groupPosition,
        boolean isExpanded,
        View convertView,
        ViewGroup parent
    ) {
        if (convertView == null) {
            convertView = LayoutInflater.from(parent.getContext()).inflate(
                android.R.layout.simple_expandable_list_item_1,
                parent,
                false
            );
        }
        TextView label = convertView.findViewById(android.R.id.text1);
        label.setText(provinces[groupPosition]);
        return convertView;
    }

    @Override
    public View getChildView(
        int groupPosition,
        int childPosition,
        boolean isLastChild,
        View convertView,
        ViewGroup parent
    ) {
        if (convertView == null) {
            convertView = LayoutInflater.from(parent.getContext()).inflate(
                android.R.layout.simple_expandable_list_item_2,
                parent,
                false
            );
        }
        TextView label = convertView.findViewById(android.R.id.text1);
        label.setText(cities[groupPosition][childPosition]);
        return convertView;
    }

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

绑定列表#

ExpandableListView list = findViewById(R.id.expandable_list);
list.setAdapter(new RegionAdapter());
省份与城市两级列表运行结果
传统 ExpandableListView 的两级列表效果。

验证#

确认每个分组可展开和收起,子项数量与数据一致,并在快速滚动后检查文字没有错位。若数据有稳定主键,应返回真实主键并将 hasStableIds() 改为 true。

参考#

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

在旧版 Android 界面中使用 ExpandableListView
https://blog.mintalix.com/posts/study-android-expand-list/
作者
Mint
发布于
2022-04-12
许可协议
CC BY-NC-SA 4.0

评论区

Profile Image of the Author
Mint
软件开发、工程实践与技术思考。
分类
标签