App下载 微信公众号

ExpandableListView的使用【Android】

技术 · 移动开发 · Android/ 作者【吾非言】/ 发布于2017-10-12/ 1.53k次浏览
2017 10/12 8:35
摘要: ExpandableListView可扩展列表,或者称其为二级列表,它能够完美的实现二级列表的显示和隐藏。也是应用中常见的控件之一。那么该如何使用ExpandableListView实现一个完整的二级列表呢?

守住心底那最美风景,成为一种风度,宁静而致远;守住记忆里最美风景,成为一种境界,悠然而豁达;守住生命中最美风景,成为一种睿智,淡定而从容。

伴职创作

ExpandableListView可扩展列表,或者称其为二级列表,它能够完美的实现二级列表的显示和隐藏。也是应用中常见的控件之一。ExpandableListView继承ListView,在实现二级列表方面表现优异,不适合多级列表的实现。那么该如何使用ExpandableListView实现一个完整的二级列表呢?
下面将以一个小案例说明ExpandableListView是如何使用。首先看看效果图:

效果图

####一、XML布局文件
ExpandableListView是Android SDK自带的一个控件,该控件继承自ListView,所以ListView的相关属性,它基本上都适合,但不是全部。

1、添加ExpandableListView到XML布局文件activity_main.xml

<ExpandableListView
    android:id="@+id/alarm_clock_expandablelist"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:childDivider="#c8c7cc"
    android:divider="@null"
    android:dividerHeight="1dp"
    android:gravity="center"
    android:listSelector="#ffffff"
    android:scrollbars="none" />

2、一级列表布局activity_main _father.xml

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

    <TextView
        android:id="@+id/alarm_clock_father_tv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:layout_centerVertical="true"
        android:padding="10dp"
        android:textSize="18sp" />

    <ImageView
        android:id="@+id/group_state"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentEnd="true"
        android:layout_alignParentRight="true"
        android:layout_centerVertical="true"
        android:layout_marginBottom="3dp"
        android:layout_marginEnd="10dp"
        android:layout_marginRight="10dp"
        android:layout_marginTop="3dp"
        android:contentDescription="@null" />

</RelativeLayout>

3、二级列表布局activity_main _children.xml

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

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="10dp"
        android:layout_marginLeft="10dp"
        android:layout_marginRight="10dp"
        android:layout_marginStart="10dp"
        android:gravity="center_vertical"
        android:orientation="vertical">

        <TextView
            android:id="@+id/alarm_clock_tv1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="18sp" />

        <TextView
            android:id="@+id/alarm_clock_tv2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="13sp" />
    </LinearLayout>

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentEnd="true"
        android:layout_alignParentRight="true"
        android:layout_centerVertical="true"
        android:contentDescription="@null"
        android:src="@drawable/right" />

</RelativeLayout>

####二、创建列表数据对象
1、一级列表数据对象,这里封装了对应二级列表数据。

public class FatherData {
    private String title;
    private ArrayList<ChildrenData> list;// 二级列表数据
    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }
    public ArrayList<ChildrenData> getList() {
        return list;
    }
    public void setList(ArrayList<ChildrenData> list) {
        this.list = list;
    }
}

2、二级列表数据对象。

public class ChildrenData {
    private String Desc;
    private String title;
    public String getDesc() {
        return Desc;
    }
    public void setDesc(String desc) {
        Desc = desc;
    }
    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }
}

####三、自定义Adapter
自定义ExPandableListView的适配器需要继承BaseExpandableListAdapter 。并实现一级列表和二级列表的相关处理方法。

public class ExPandableListViewAdapter extends BaseExpandableListAdapter {
    // 定义一个Context
    private Context context;
    // 定义一个LayoutInflater
    private LayoutInflater mInflater;
    // 定义一个List来保存列表数据
    private ArrayList<FatherData> data_list = new ArrayList<>();

    // 定义一个构造方法
    public ExPandableListViewAdapter(Context context, ArrayList<FatherData> datas) {
        this.context = context;
        this.mInflater = LayoutInflater.from(context);
        this.data_list = datas;
    }

    // 刷新数据
    public void flashData(ArrayList<FatherData> datas) {
        this.data_list = datas;
        this.notifyDataSetChanged();
    }

    // 获取二级列表的内容
    @Override
    public Object getChild(int arg0, int arg1) {
        return data_list.get(arg0).getList().get(arg1);
    }

    // 获取二级列表的ID
    @Override
    public long getChildId(int arg0, int arg1) {
        return arg1;
    }

    // 定义二级列表中的数据
    @Override
    public View getChildView(int arg0, int arg1, boolean arg2, View arg3, ViewGroup arg4) {
        // 定义一个二级列表的视图类
        HolderView childrenView;
        if (arg3 == null) {
            childrenView = new HolderView();
            // 获取子视图的布局文件
            arg3 = mInflater.inflate(R.layout.activity_main_children, arg4, false);
            childrenView.titleView = (TextView) arg3.findViewById(R.id.alarm_clock_tv1);
            childrenView.descView = (TextView) arg3.findViewById(R.id.alarm_clock_tv2);
            // 这个函数是用来将holderview设置标签,相当于缓存在view当中
            arg3.setTag(childrenView);
        } else {
            childrenView = (HolderView) arg3.getTag();
        }

        /**
         * 设置相应控件的内容
         */
        // 设置标题上的文本信息
        childrenView.titleView.setText(data_list.get(arg0).getList().get(arg1).getTitle());
        // 设置副标题上的文本信息
        childrenView.descView.setText(data_list.get(arg0).getList().get(arg1).getDesc());
        return arg3;
    }

    // 保存二级列表的视图类
    private class HolderView {
        TextView titleView;
        TextView descView;
    }

    // 获取二级列表的数量
    @Override
    public int getChildrenCount(int arg0) {
        return data_list.get(arg0).getList().size();
    }

    // 获取一级列表的数据
    @Override
    public Object getGroup(int arg0) {
        return data_list.get(arg0);
    }

    // 获取一级列表的个数
    @Override
    public int getGroupCount() {
        return data_list.size();
    }

    // 获取一级列表的ID
    @Override
    public long getGroupId(int arg0) {
        return arg0;
    }

    // 设置一级列表的view
    @Override
    public View getGroupView(int arg0, boolean arg1, View arg2, ViewGroup arg3) {
        HodlerViewFather hodlerViewFather;
        if (arg2 == null) {
            hodlerViewFather = new HodlerViewFather();
            arg2 = mInflater.inflate(R.layout.activity_main_father, arg3, false);
            hodlerViewFather.titlev = (TextView) arg2.findViewById(R.id.alarm_clock_father_tv);
            // 新建一个TextView对象,用来显示一级标签上的大体描述的信息
            hodlerViewFather.group_state = (ImageView) arg2.findViewById(R.id.group_state);
            arg2.setTag(hodlerViewFather);
        } else {
            hodlerViewFather = (HodlerViewFather) arg2.getTag();
        }
        // 一级列表右侧判断箭头显示方向
        if (arg1) {
            hodlerViewFather.group_state.setImageResource(R.drawable.group_down);
        } else {
            hodlerViewFather.group_state.setImageResource(R.drawable.group_up);
        }
        /**
         * 设置相应控件的内容
         */
        // 设置标题上的文本信息
        hodlerViewFather.titlev.setText(data_list.get(arg0).getTitle());

        // 返回一个布局对象
        return arg2;
    }

    // 定义一个 一级列表的view类
    private class HodlerViewFather {
        TextView titlev;
        ImageView group_state;
    }

    /**
     * 指定位置相应的组视图
     */
    @Override
    public boolean hasStableIds() {
        return true;
    }

    /**
     * 当选择子节点的时候,调用该方法(点击二级列表)
     */
    @Override
    public boolean isChildSelectable(int arg0, int arg1) {
        return true;
    }
}

####四、Activity实现
ExPandableListView提供对一级列表和二级列表的点击事件监听,分别是OnGroupClickListener、OnChildClickListener。

public class MainActivity extends AppCompatActivity {
    private ExpandableListView myExpandableListView;
    private ExPandableListViewAdapter adapter;
    private ArrayList<FatherData> datas;

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

        initView();
        setData();
        setAdapter();
    }

    // 初始化控件
    private void initView() {
        myExpandableListView = (ExpandableListView) findViewById(R.id.alarm_clock_expandablelist);
        // 设置ExpandableListView的监听事件
        // 设置一级item点击的监听器
        myExpandableListView.setOnGroupClickListener(new OnGroupClickListener() {
            @Override
            public boolean onGroupClick(ExpandableListView arg0, View arg1, int arg2, long arg3) {
                // TODO Auto-generated method stub
                Toast.makeText(MainActivity.this, datas.get(arg2).getTitle(), Toast.LENGTH_LONG).show();
                return false;
            }
        });

        // 设置二级item点击的监听器,同时在Adapter中设置isChildSelectable返回值true,同时二级列表布局中控件不能设置点击效果
        myExpandableListView.setOnChildClickListener(new OnChildClickListener() {
            @Override
            public boolean onChildClick(ExpandableListView arg0, View arg1, int arg2, int arg3, long arg4) {
                // TODO Auto-generated method stub
                Toast.makeText(MainActivity.this, datas.get(arg2).getList().get(arg3).getTitle(), Toast.LENGTH_LONG).show();
                return false;
            }
        });
    }

    /**
     * 自定义setAdapter
     */
    private void setAdapter() {
        if (adapter == null) {
            adapter = new ExPandableListViewAdapter(this, datas);
            myExpandableListView.setAdapter(adapter);
        } else {
            adapter.flashData(datas);
        }
    }

    // 定义数据
    private void setData() {
        if (datas == null) {
            datas = new ArrayList<>();
        }
        // 一级列表中的数据
        for (int i = 0; i < 5; i++) {
            FatherData fatherData = new FatherData();
            fatherData.setTitle("闹钟列表" + i);
            // 二级列表中的数据
            ArrayList<ChildrenData> itemList = new ArrayList<>();
            for (int j = 0; j < 3; j++) {
                ChildrenData childrenData = new ChildrenData();
                childrenData.setTitle("闹钟主题" + j);
                childrenData.setDesc(j + ":30");
                itemList.add(childrenData);
            }
            fatherData.setList(itemList);
            datas.add(fatherData);
        }
    }
}

以上便是实现可扩展列表的基本使用规则。
####ExPandableListView其他设置
(1)、去掉默认带的箭头

expandlistView.setGroupIndicator(null);

(2)、设置默认选中项

expandlistView.setSelection(0);

(3)、所有项设置成默认展开

// 遍历所有group,将所有项设置成默认展开
int groupCount = expandlistView.getCount();
for (int i = 0; i < groupCount; i++) {
    expandlistView.expandGroup(i);
}

####ExPandableListView常见问题
在开发过程常常会遇到ExPandableListView二级列表点击没有反应,那么该如何正确实现二级列表的点击事件呢?

一、需要在Adapter复写isChildSelectable方法,设置返回值为true。

@Override
public boolean isChildSelectable(int arg0, int arg1) {
        return true;
}

二、如果这样二级列表点击还没有效果的话,检查看看二级布局文件是不是设置了布局点击事件,如果二级列表布局已经设置了点击事件就去掉布局的点击事件。

三、如果以上两种方式都处理了,还是无法设置二级列表的点击事件,那就检查二级列表布局文件中是否含有像ToggleButton这样原本就具有点击效果的控件,如果有就去掉。

Github地址

微信公众号:伴职创作

感谢您使用伴职平台,如有侵权,请投诉删除!

全部评价

最新
查看更多评论 加载

猜你喜欢

换一批