Android ExpandableListView用法示例詳解
引言
在 Android 開發(fā)中,列表展示是一種非常常見的交互形式。而 ExpandableListView 作為一種特殊的列表控件,它允許我們創(chuàng)建具有分組功能的列表,每個(gè)分組下還可以包含多個(gè)子項(xiàng),并且分組可以展開和收縮,這大大增強(qiáng)了數(shù)據(jù)展示的靈活性和可讀性。本文將詳細(xì)介紹 ExpandableListView 的用法,從基本概念到具體實(shí)現(xiàn),再到高級(jí)應(yīng)用,幫助你全面掌握這一控件。
1. ExpandableListView 基本概念
ExpandableListView 繼承自 ListView,是 Android 提供的一種可展開的列表視圖。它主要由分組(Group)和子項(xiàng)(Child)兩部分組成。每個(gè)分組可以包含多個(gè)子項(xiàng),用戶可以通過點(diǎn)擊分組來展開或收縮其對(duì)應(yīng)的子項(xiàng)列表。這種控件適用于需要對(duì)數(shù)據(jù)進(jìn)行分類展示的場景,例如聯(lián)系人列表按照字母分組、商品列表按照類別分組等。
2. 布局文件中添加 ExpandableListView
首先,我們需要在布局文件中添加 ExpandableListView 控件。以下是一個(gè)簡單的示例:
<!-- activity_main.xml --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <ExpandableListView android:id="@+id/expandableListView" android:layout_width="match_parent" android:layout_height="match_parent" /> </LinearLayout>
在這個(gè)布局中,我們創(chuàng)建了一個(gè)垂直的線性布局,并在其中添加了一個(gè) ExpandableListView,其寬度和高度都設(shè)置為 match_parent,以填充整個(gè)父布局。
3. 創(chuàng)建數(shù)據(jù)模型
為了展示分組和子項(xiàng)的數(shù)據(jù),我們需要?jiǎng)?chuàng)建相應(yīng)的數(shù)據(jù)模型類。假設(shè)我們要展示一個(gè)水果分類列表,每個(gè)分類下有不同的水果,我們可以創(chuàng)建如下的數(shù)據(jù)模型類:
// GroupModel.java public class GroupModel { private String groupName; public GroupModel(String groupName) { this.groupName = groupName; } public String getGroupName() { return groupName; } public void setGroupName(String groupName) { this.groupName = groupName; } } // ChildModel.java public class ChildModel { private String childName; public ChildModel(String childName) { this.childName = childName; } public String getChildName() { return childName; } public void setChildName(String childName) { this.childName = childName; } }
GroupModel 類用于表示分組信息,包含一個(gè)分組名稱;ChildModel 類用于表示子項(xiàng)信息,包含一個(gè)子項(xiàng)名稱。
4. 創(chuàng)建適配器
ExpandableListView 需要使用適配器來將數(shù)據(jù)綁定到視圖上。我們可以繼承 BaseExpandableListAdapter 類來創(chuàng)建自定義適配器。以下是一個(gè)示例:
import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseExpandableListAdapter; import android.widget.TextView; import java.util.List; public class MyExpandableListAdapter extends BaseExpandableListAdapter { private Context context; private List<GroupModel> groupList; private List<List<ChildModel>> childList; public MyExpandableListAdapter(Context context, List<GroupModel> groupList, List<List<ChildModel>> childList) { this.context = context; this.groupList = groupList; this.childList = childList; } @Override public int getGroupCount() { return groupList.size(); } @Override public int getChildrenCount(int groupPosition) { return childList.get(groupPosition).size(); } @Override public Object getGroup(int groupPosition) { return groupList.get(groupPosition); } @Override public Object getChild(int groupPosition, int childPosition) { return childList.get(groupPosition).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 false; } @Override public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) { GroupModel groupModel = (GroupModel) getGroup(groupPosition); if (convertView == null) { LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); convertView = inflater.inflate(android.R.layout.simple_expandable_list_item_1, null); } TextView groupTextView = convertView.findViewById(android.R.id.text1); groupTextView.setText(groupModel.getGroupName()); return convertView; } @Override public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) { ChildModel childModel = (ChildModel) getChild(groupPosition, childPosition); if (convertView == null) { LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); convertView = inflater.inflate(android.R.layout.simple_list_item_1, null); } TextView childTextView = convertView.findViewById(android.R.id.text1); childTextView.setText(childModel.getChildName()); return convertView; } @Override public boolean isChildSelectable(int groupPosition, int childPosition) { return true; } }
在這個(gè)適配器中,我們需要實(shí)現(xiàn)一系列的方法:
- getGroupCount():返回分組的數(shù)量。
- getChildrenCount(int groupPosition):返回指定分組下子項(xiàng)的數(shù)量。
- getGroup(int groupPosition):返回指定位置的分組對(duì)象。
- getChild(int groupPosition, int childPosition):返回指定分組下指定位置的子項(xiàng)對(duì)象。
- getGroupId(int groupPosition) 和 getChildId(int groupPosition, int childPosition):分別返回分組和子項(xiàng)的 ID。
- getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent):創(chuàng)建并返回分組的視圖。
- getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent):創(chuàng)建并返回子項(xiàng)的視圖。
- isChildSelectable(int groupPosition, int childPosition):指定子項(xiàng)是否可以被選中。
5. 在 Activity 中使用 ExpandableListView
在 Activity 中,我們需要初始化數(shù)據(jù)、創(chuàng)建適配器并將其設(shè)置給 ExpandableListView。以下是示例代碼:
import android.os.Bundle; import android.widget.ExpandableListView; import androidx.appcompat.app.AppCompatActivity; import java.util.ArrayList; import java.util.List; public class MainActivity extends AppCompatActivity { private ExpandableListView expandableListView; private MyExpandableListAdapter adapter; private List<GroupModel> groupList; private List<List<ChildModel>> childList; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); expandableListView = findViewById(R.id.expandableListView); // 初始化數(shù)據(jù) initData(); // 創(chuàng)建適配器 adapter = new MyExpandableListAdapter(this, groupList, childList); // 設(shè)置適配器 expandableListView.setAdapter(adapter); } private void initData() { groupList = new ArrayList<>(); childList = new ArrayList<>(); // 添加分組數(shù)據(jù) GroupModel group1 = new GroupModel("熱帶水果"); GroupModel group2 = new GroupModel("溫帶水果"); groupList.add(group1); groupList.add(group2); // 為每個(gè)分組添加子項(xiàng)數(shù)據(jù) List<ChildModel> childList1 = new ArrayList<>(); childList1.add(new ChildModel("香蕉")); childList1.add(new ChildModel("芒果")); childList.add(childList1); List<ChildModel> childList2 = new ArrayList<>(); childList2.add(new ChildModel("蘋果")); childList2.add(new ChildModel("梨")); childList.add(childList2); } }
在 onCreate 方法中,我們首先獲取 ExpandableListView 控件的引用,然后調(diào)用 initData 方法初始化數(shù)據(jù),接著創(chuàng)建適配器并將其設(shè)置給 ExpandableListView。
6. 處理分組和子項(xiàng)的點(diǎn)擊事件
我們可以為 ExpandableListView 添加分組和子項(xiàng)的點(diǎn)擊事件監(jiān)聽器,以實(shí)現(xiàn)相應(yīng)的交互邏輯。以下是示例代碼:
// 在 onCreate 方法中添加以下代碼 expandableListView.setOnGroupClickListener(new ExpandableListView.OnGroupClickListener() { @Override public boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long id) { // 處理分組點(diǎn)擊事件 GroupModel groupModel = (GroupModel) adapter.getGroup(groupPosition); String groupName = groupModel.getGroupName(); // 這里可以添加自定義的邏輯,比如彈出提示框顯示分組名稱 return false; } }); expandableListView.setOnChildClickListener(new ExpandableListView.OnChildClickListener() { @Override public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) { // 處理子項(xiàng)點(diǎn)擊事件 ChildModel childModel = (ChildModel) adapter.getChild(groupPosition, childPosition); String childName = childModel.getChildName(); // 這里可以添加自定義的邏輯,比如跳轉(zhuǎn)到詳情頁面 return false; } });
在分組點(diǎn)擊事件監(jiān)聽器中,我們可以獲取點(diǎn)擊的分組對(duì)象并進(jìn)行相應(yīng)的處理;在子項(xiàng)點(diǎn)擊事件監(jiān)聽器中,我們可以獲取點(diǎn)擊的子項(xiàng)對(duì)象并進(jìn)行相應(yīng)的處理。
7. 高級(jí)應(yīng)用:自定義視圖
除了使用系統(tǒng)提供的簡單布局,我們還可以自定義分組和子項(xiàng)的視圖,以實(shí)現(xiàn)更豐富的界面效果。以下是一個(gè)自定義視圖的示例:
自定義分組布局文件 group_item.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:padding="10dp"> <ImageView android:id="@+id/group_icon" android:layout_width="24dp" android:layout_height="24dp" android:src="@mipmap/ic_launcher" /> <TextView android:id="@+id/group_name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="10dp" android:textSize="18sp" /> </LinearLayout>
自定義子項(xiàng)布局文件 child_item.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:padding="10dp"> <ImageView android:id="@+id/child_icon" android:layout_width="24dp" android:layout_height="24dp" android:src="@mipmap/ic_launcher" /> <TextView android:id="@+id/child_name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="10dp" android:textSize="16sp" /> </LinearLayout>
修改適配器中的 getGroupView 和 getChildView 方法
@Override public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) { GroupModel groupModel = (GroupModel) getGroup(groupPosition); if (convertView == null) { LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); convertView = inflater.inflate(R.layout.group_item, null); } ImageView groupIcon = convertView.findViewById(R.id.group_icon); TextView groupTextView = convertView.findViewById(R.id.group_name); groupTextView.setText(groupModel.getGroupName()); return convertView; } @Override public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) { ChildModel childModel = (ChildModel) getChild(groupPosition, childPosition); if (convertView == null) { LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); convertView = inflater.inflate(R.layout.child_item, null); } ImageView childIcon = convertView.findViewById(R.id.child_icon); TextView childTextView = convertView.findViewById(R.id.child_name); childTextView.setText(childModel.getChildName()); return convertView; }
通過自定義視圖,我們可以在分組和子項(xiàng)中添加更多的控件,如圖片、按鈕等,從而實(shí)現(xiàn)更復(fù)雜的界面效果。
8. 總結(jié)
ExpandableListView 是 Android 中一個(gè)非常實(shí)用的列表控件,它可以幫助我們實(shí)現(xiàn)具有分組功能的列表展示。通過本文的介紹,你應(yīng)該已經(jīng)掌握了 ExpandableListView 的基本用法,包括布局文件的添加、數(shù)據(jù)模型的創(chuàng)建、適配器的實(shí)現(xiàn)、點(diǎn)擊事件的處理以及自定義視圖的應(yīng)用。在實(shí)際開發(fā)中,你可以根據(jù)具體需求對(duì)其進(jìn)行進(jìn)一步的擴(kuò)展和優(yōu)化,以滿足不同的業(yè)務(wù)場景。希望本文對(duì)你有所幫助,祝你在 Android 開發(fā)中取得更好的成果!
- Android ExpandableListView雙層嵌套實(shí)現(xiàn)三級(jí)樹形菜單
- Android ExpandableListView實(shí)現(xiàn)下拉刷新和加載更多效果
- Android ExpandableListView單選以及多選實(shí)現(xiàn)代碼
- Android ScrollView嵌套ExpandableListView顯示不正常的問題的解決辦法
- Android listview ExpandableListView實(shí)現(xiàn)多選,單選,全選,edittext實(shí)現(xiàn)批量輸入的實(shí)例代碼
- Android 關(guān)于ExpandableListView刷新問題的解決方法
- Android 關(guān)于ExpandableListView去掉里頭分割線的方法
- Android UI控件ExpandableListView基本用法詳解
- Android改變ExpandableListView的indicator圖標(biāo)實(shí)現(xiàn)方法
- Android中ExpandableListView的用法實(shí)例
- Android ExpandableListView展開列表控件使用實(shí)例
相關(guān)文章
Android app開發(fā)中的Fragment入門學(xué)習(xí)教程
這篇文章主要介紹了Android app開發(fā)中的Fragment入門學(xué)習(xí)教程,包括Fragment的創(chuàng)建和XML布局文件中的Fragment定義等,需要的朋友可以參考下2016-02-02Android升級(jí)支持庫版本遇到的兩個(gè)問題詳解
安卓平臺(tái)其中一個(gè)很牛逼的地方在于它支持各種不同的設(shè)備。從你的平板電腦,到你的手機(jī),電視等,安卓無處不在。這篇文章主要給大家介紹了關(guān)于Android升級(jí)支持庫版本遇到的兩個(gè)問題,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面來一起看看吧。2017-10-10Android仿微信列表滑動(dòng)刪除 如何實(shí)現(xiàn)滑動(dòng)列表SwipeListView
這篇文章主要為大家詳細(xì)介紹了Android仿微信列表滑動(dòng)刪除,如何實(shí)現(xiàn)滑動(dòng)列表SwipeListView,感興趣的小伙伴們可以參考一下2016-08-08Android自定義相機(jī)界面的實(shí)現(xiàn)代碼
這篇文章主要為大家詳細(xì)介紹了Android自定義相機(jī)界面的實(shí)現(xiàn)代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-11-11Android實(shí)現(xiàn)支付寶螞蟻森林水滴浮動(dòng)效果
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)支付寶螞蟻森林水滴浮動(dòng)效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-06-06Android開發(fā)高級(jí)組件之自動(dòng)完成文本框(AutoCompleteTextView)用法示例【附源碼下載】
這篇文章主要介紹了Android開發(fā)高級(jí)組件之自動(dòng)完成文本框(AutoCompleteTextView)用法,簡單描述了自動(dòng)完成文本框的功能并結(jié)合實(shí)例形式分析了Android實(shí)現(xiàn)自動(dòng)完成文本框功能的具體步驟與相關(guān)操作技巧,并附帶源碼供讀者下載參考,需要的朋友可以參考下2018-01-01使用Broadcast實(shí)現(xiàn)Android組件間的通信
這篇文章主要為大家詳細(xì)介紹了使用Broadcast實(shí)現(xiàn)Android組件間的通信,感興趣的小伙伴們可以參考一下2016-06-06Android自定義SurfaceView實(shí)現(xiàn)畫板功能
這篇文章主要為大家詳細(xì)介紹了Android自定義SurfaceView實(shí)現(xiàn)畫板功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-07-07