ExpandableListView 二级菜单的使用方式

博主声明:
转载请在开头附加本文链接及作者信息,并标记为转载。本文由博主 威威喵 原创,请多支持与指教。
本文首发于此 博主:威威喵 | 博客主页:https://blog.csdn.net/smile_running

在 Android 开发中,一个 App 通常会有这种的需求,就是在一个列表内部在嵌套一个列表,下面我们来看看效果图就知道了。
ExpandableListView 二级菜单的使用方式_第1张图片

Android 二级菜单的简单使用方式

首先呢,我们要准备一个处理 ExpandableListView 的数据的适配器,只需继承BaseExpandableListAdapter 重写里面的方法即可。下面我们来看看这个代码吧:

/**
 * @author xww
 * @desciption : ExpandableListView 适配器
 * @date 2019/10/24
 * @time 16:10
 */
public class CitySelectAdapter extends BaseExpandableListAdapter {

    private Context mContext;
    private List<CitySelectBean> mDataBeans;

    public CitySelectAdapter(Context context, List<CitySelectBean> citySelectBeans) {
        this.mContext = context;
        this.mDataBeans = citySelectBeans;
    }

    @Override
    public int getGroupCount() {
        return mDataBeans.size();
    }

    @Override
    public int getChildrenCount(int groupPosition) {
        return mDataBeans.get(groupPosition).getCity().size();
    }

    @Override
    public Object getGroup(int groupPosition) {
        return mDataBeans.get(groupPosition);
    }

    @Override
    public Object getChild(int groupPosition, int childPosition) {
        return mDataBeans.get(groupPosition).getCity().get(childPosition);
    }

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

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

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

    @Override
    public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
        GroupHolder holder = null;
        if (convertView == null) {
            convertView = LayoutInflater.from(mContext).inflate(R.layout.exp_list_city_select_province, null);
            holder = new GroupHolder(convertView);

            convertView.setTag(holder);
        } else {
            holder = (GroupHolder) convertView.getTag();
        }
        holder.tvProvince.setText(mDataBeans.get(groupPosition).getProvince());
        return convertView;
    }

    @Override
    public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
        ChildHolder holder = null;
        if (convertView == null) {
            convertView = LayoutInflater.from(mContext).inflate(R.layout.exp_list_city_select_city, null);
            holder = new ChildHolder(convertView);

            convertView.setTag(holder);
        } else {
            holder = (ChildHolder) convertView.getTag();
        }
        holder.tvCity.setText(mDataBeans.get(groupPosition).getCity().get(childPosition));
        return convertView;
    }

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

    public class GroupHolder {
        TextView tvProvince;

        GroupHolder(View itemView) {
            tvProvince = itemView.findViewById(R.id.exp_list_province);
        }
    }

    public class ChildHolder {
        TextView tvCity;

        ChildHolder(View itemView) {
            tvCity = itemView.findViewById(R.id.exp_list_city);
        }
    }
}

看这个适配器给我们提供的方法,就很容易知道我们要传入的一个数据模型,下面我就拿省份、城市来举个例子。我们的一级列表是省份,二级列表里面是各个省的城市。它的数据模型是这样样子的:


/**
 * @author xww
 * @desciption :
 * @date 2019/10/24
 * @time 16:08
 */
public class CitySelectBean {

    private String province;
    private List<String> city;

    public CitySelectBean(String province, List<String> city) {
        this.province = province;
        this.city = city;
    }

    public String getProvince() {
        return province;
    }

    public void setProvince(String province) {
        this.province = province;
    }

    public List<String> getCity() {
        return city;
    }

    public void setCity(List<String> city) {
        this.city = city;
    }
}

由于提供的数据比较简单,那么适配器的 item 布局就放一个 TextView 即可,但是这里要分清楚,一共有两个 item 布局,一个是省份的,一个是城市的,代码如下:


<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <TextView
        android:id="@+id/exp_list_province"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layoutDirection="ltr"
        android:padding="8dp" />
RelativeLayout>

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <TextView
        android:id="@+id/exp_list_city"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="8dp"
        android:layoutDirection="ltr"
        android:paddingLeft="24dp"
        android:paddingBottom="8dp" />
RelativeLayout>

那么到此,我们的适配器以及布局文件就准备好了,然后是我们的 Activity 的布局文件:


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/colorWhite"
    android:orientation="vertical">

    <TextView
        style="@style/TopTitleBarStyle"
        android:layout_width="match_parent"
        android:layout_height="48dp"
        android:text="选择城市" />

    <ExpandableListView
        android:id="@+id/explv_city_select"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layoutDirection="rtl" />
LinearLayout>

最后,就是我们如何添加数据了, Activity 的代码如下:

/**
 * @author xww
 * @desciption :
 * @date 2019/10/24
 * @time 16:01
 */
public class CitySelectActivity extends BasePermissionActivity {

    private ExpandableListView explvCity;
    private CitySelectAdapter mCitySelectAdapter;
    private List<CitySelectBean> mCitySelectBeans;

    @Override
    protected void initLayout(@Nullable Bundle savedInstanceState) {
        super.initLayout(savedInstanceState);
        setContentView(R.layout.activity_city_select);
    }

    @Override
    protected void initViews() {
        super.initViews();
        explvCity = $(R.id.explv_city_select);
    }

    @Override
    protected void initData() {
        super.initData();
        mCitySelectBeans = new ArrayList<>();
        mCitySelectBeans.add(new CitySelectBean("福建省", Arrays.asList("宁德", "福州", "厦门", "漳州", "泉州")));
        mCitySelectBeans.add(new CitySelectBean("广东省", Arrays.asList("汕头", "东菀", "深圳", "广州")));
        mCitySelectBeans.add(new CitySelectBean("浙江省", Arrays.asList("温州", "杭州", "绍兴", "嘉兴")));

        mCitySelectAdapter = new CitySelectAdapter(this, mCitySelectBeans);
        explvCity.setAdapter(mCitySelectAdapter);
    }
}

这里有一个属性介绍一下

android:layoutDirection="rtl"

这个属性是把如下图的那个箭头设置到右边,因为在左边时会被文字给挡住了,显得不好看。
ExpandableListView 二级菜单的使用方式_第2张图片
下面是 ExpandableListView 的 Item 点击事件,这个肯定会使用得到,代码也很简单,如下:

        // 设置一级列表点击事件
        explvCity.setOnGroupClickListener((parent, v, groupPosition, id) -> {
            String province = mCitySelectBeans.get(groupPosition).getProvince();
            return false;
        });
        // 设置二级列表点击事件
        explvCity.setOnChildClickListener((parent, v, groupPosition, childPosition, id) -> {
            String city = mCitySelectBeans.get(groupPosition).getCity().get(childPosition);
            return false;
        });

还有会遇到二级菜单是默认收起来的问题,如果你需要让 ExpandableListView 的二级菜单每一个都是展开的效果,可以这样做,代码如下:

        int count = explvCity.getCount();   //这里一定要这样写
        for (int i = 0; i < count; i++) {
            explvCity.expandGroup(i);
        }

如果你要这样写的话,它会抛出下标越界异常

        for (int i = 0; i < explvCity.getCount(); i++) {
            explvCity.expandGroup(i);
        }

你可能感兴趣的:(Android,#,初级之路)