在做手机app开发的过程中通常数据列表展示都是一级的,通常用的组件也就是 ListView,GridView。但是有的时候会用到二级列列表,或者三级列表。今天我们就介绍一下二级树形列表如何实现:
今天要用到 ExpandableListView组件来实现可折叠列表功能。
首先我们先找一下一个小案例,看看菜鸟教程是如何做的。菜鸟教程链接:https://www.runoob.com/w3cnote/android-tutorial-expandablelistview.html
教程的实现结果是:
看上去使我们想要实现的结果,但是在实际开发中也要考虑实际情况的。所以把它拿来用也要根据自己的业务情况做一下改进。
首先自定义一个类MyExpandableListAdapter继承基类BaseExpandableListAdapter并实现其所有方法,每个重写方法表示什么意思,已经标注:
package com.example.appview.Common.ThreeTree; import android.view.View; import android.view.ViewGroup; import android.widget.BaseExpandableListAdapter; public class MyExpanableListAdapterHelper extends BaseExpandableListAdapter { //组数量 @Override public int getGroupCount() { return 0; } //子View数量 @Override public int getChildrenCount(int groupPosition) { return 0; } //获取组对象 @Override public Object getGroup(int groupPosition) { return null; } //获取子View对象 @Override public Object getChild(int groupPosition, int childPosition) { return null; } // 组View下标 @Override public long getGroupId(int groupPosition) { return 0; } //子View下标 @Override public long getChildId(int groupPosition, int childPosition) { return 0; } //不知道做什么用 @Override public boolean hasStableIds() { return false; } //取得用于显示给定分组的视图. 这个方法仅返回分组的视图对象 @Override public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) { return null; } //取得显示给定分组给定子位置的数据用的视图 @Override public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) { return null; } @Override public boolean isChildSelectable(int groupPosition, int childPosition) { return false; } }
我们就以机楼和采集器的关系做一个二级树形列表,一个机楼可能安装多个采集器:
定义一个机楼,采集模型:
package com.example.appview.mian_page.Frament.Preject_Tance_Frament.ItemA_Model; import android.provider.ContactsContract; import java.util.Date; import java.util.List; public class JiLouModel { private int JiLouId;//机楼ID private String JiLouName;//机楼名字 private String Path;//图片路径 private Date AddTime;//添加时间 private List<CaiJiModel> CaiJiList; public void setJiLouId(int jiLouId) { JiLouId = jiLouId; } public int getJiLouId() { return JiLouId; } public void setJiLouName(String jiLouName) { JiLouName = jiLouName; } public String getJiLouName() { return JiLouName; } public void setPath(String path) { Path = path; } public String getPath() { return Path; } public void setAddTime(Date addTime) { AddTime = addTime; } public Date getAddTime() { return AddTime; } public void setCaiJiList(List<CaiJiModel> caiJiList) { CaiJiList = caiJiList; } public List<CaiJiModel> getCaiJiList() { return CaiJiList; } static class CaiJiModel { private int CaiJiId;//采集器 private String CaiJiNumber;//采集器编号 private String Path;//图片路径 private Date AddTime;//添加时间 public void setCaiJiId(int caiJiId) { CaiJiId = caiJiId; } public int getCaiJiId() { return CaiJiId; } public void setCaiJiNumber(String caiJiNumber) { CaiJiNumber = caiJiNumber; } public String getCaiJiNumber() { return CaiJiNumber; } public void setAddTime(Date addTime) { AddTime = addTime; } public Date getAddTime() { return AddTime; } public void setPath(String path) { Path = path; } public String getPath() { return Path; } } }
对MyExpanableListAdapterHelper稍作修改:
package com.example.appview.Common.ThreeTree; 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 com.example.appview.R; import com.example.appview.mian_page.Frament.Preject_Tance_Frament.ItemA_Model.JiLou; import com.example.appview.mian_page.Frament.Preject_Tance_Frament.ItemA_Model.JiLouModel; import java.util.List; public class MyExpanableListAdapterHelper extends BaseExpandableListAdapter { private Context context; public List<JiLou> JilouModellist; LayoutInflater layoutInflater; public MyExpanableListAdapterHelper(Context context, List<JiLou> JilouModellist){ this.JilouModellist=JilouModellist; layoutInflater = LayoutInflater.from(context); } //组数量 @Override public int getGroupCount() { return JilouModellist.size(); } //子View数量 @Override public int getChildrenCount(int groupPosition) { return JilouModellist.get(groupPosition).getCaiJiList().size(); } //获取组对象 @Override public Object getGroup(int groupPosition) { return JilouModellist.get(groupPosition); } //获取子View对象 @Override public Object getChild(int groupPosition, int childPosition) { return JilouModellist.get(groupPosition).getCaiJiList().get(childPosition); } // 组View下标 @Override public long getGroupId(int groupPosition) { return groupPosition; } //子View下标 @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) { convertView= layoutInflater.inflate(R.layout.preject_item_addcaiji_onetree, null); TextView textView = convertView.findViewById(R.id.preject_item_caijiqi_onetree); textView.setText(JilouModellist.get(groupPosition).getJiLouName()); return convertView; } //取得显示给定分组给定子位置的数据用的视图 @Override public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) { convertView= layoutInflater.inflate(R.layout.preject_item_addcaiji_twotree, null); convertView.setPadding(50,5,0,5); TextView textView = convertView.findViewById(R.id.preject_item_dianbiao); textView.setText(JilouModellist.get(groupPosition).getCaiJiList().get(childPosition).getCaiJiNumber()); return convertView; } @Override public boolean isChildSelectable(int groupPosition, int childPosition) { return false; } }
preject_item_addcaiji_onetree 布局:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@color/white" android:orientation="horizontal"> <LinearLayout android:layout_width="match_parent" android:layout_height="50dp" android:descendantFocusability="blocksDescendants" android:background="@drawable/mainpage_gridview" android:elevation="10dp" android:orientation="horizontal"> <LinearLayout android:id="@+id/preject_item_layout_onetree" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1"> <ImageView android:layout_width="40dp" android:layout_marginLeft="10dp" android:layout_gravity="center" android:background="@mipmap/preject_item_caijiqi" android:layout_height="40dp"/> </LinearLayout> <TextView android:id="@+id/preject_item_caijiqi_onetree" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:gravity="center" android:text="采集器编号" android:textColor="@color/black"/> <TextView android:id="@+id/preject_item_addtime_onetree" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="2" android:text="2021-08-12 11:19:00" android:textColor="@color/black" android:gravity="center" /> <LinearLayout android:layout_width="0dp" android:id="@+id/preject_item_imagecaiji_onetree" android:layout_height="match_parent" android:focusable="false" android:clickable="true" android:layout_weight="1"> <ImageView android:id="@+id/preject_item_caijiqi" android:layout_width="30dp" android:layout_height="30dp" android:background="@mipmap/preject_item_caozuo" android:layout_gravity="center" android:layout_marginLeft="20dp"/> </LinearLayout> </LinearLayout> </LinearLayout>
preject_item_addcaiji_twotree布局:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@color/white" android:orientation="horizontal"> <LinearLayout android:layout_width="match_parent" android:layout_height="50dp" android:background="@drawable/mainpage_gridview" android:elevation="10dp" android:descendantFocusability="blocksDescendants" android:orientation="horizontal"> <LinearLayout android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1"> <ImageView android:id="@+id/preject_item_jztype" android:layout_width="40dp" android:layout_marginLeft="10dp" android:layout_gravity="center" android:background="@mipmap/preject_item_dianbiao" android:layout_height="40dp"/> </LinearLayout> <TextView android:id="@+id/preject_item_dianbiao" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:gravity="center" android:text="电表表号" android:textColor="@color/black"/> <TextView android:id="@+id/preject_item_dianbiao_address" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:text="通信地址" android:textColor="@color/black" android:gravity="center" /> <TextView android:id="@+id/preject_item_addtime_twotree" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="2" android:text="2021-08-12 11:19:00" android:textColor="@color/black" android:gravity="center"/> <LinearLayout android:layout_width="0dp" android:id="@+id/preject_item_layoutcaozuo_twotree" android:focusable="false" android:clickable="true" android:layout_height="match_parent" android:layout_weight="1"> <ImageView android:id="@+id/preject_item_dianbiao_caozuo" android:layout_width="30dp" android:layout_height="30dp" android:layout_gravity="center" android:background="@mipmap/preject_item_caozuo" android:layout_marginLeft="20dp" /> </LinearLayout> </LinearLayout> </LinearLayout>
新建一个Demo Activity:
package com.example.appview; import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.ExpandableListView; import android.widget.LinearLayout; import android.widget.TextView; import android.widget.Toast; import com.example.appview.Common.ThreeTree.MyExpanableListAdapterHelper; import com.example.appview.mian_page.Frament.Preject_Tance_Frament.ItemA_Model.JiLou; import com.example.appview.mian_page.Frament.Preject_Tance_Frament.ItemA_Model.JiLouModel; import com.example.appview.mian_page.Frament.Preject_Tance_Frament.ItemA_Model.ThreeTreeModel; import com.example.appview.mian_page.Frament.Preject_Tance_Frament.ItemA_Model.Tree.ExpandableListViewInterface; import com.example.appview.mian_page.Frament.Preject_Tance_Frament.ItemA_Model.Tree.ParentAdapterHelper; import java.util.ArrayList; import java.util.Date; import java.util.List; public class Demo extends AppCompatActivity { private ExpandableListView expandableListView; List<JiLou> jiLouModels=new ArrayList<>(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_demo); expandableListView = findViewById(R.id.expandable_listView); initData(); MyExpanableListAdapterHelper adapterHelper=new MyExpanableListAdapterHelper(Demo.this,jiLouModels); //ParentAdapterHelper<One,Two,Three> adapterHelper=new ParentAdapterHelper(this,threeTreeModels,new One(),new Two(),new Three()); expandableListView .setAdapter(adapterHelper); } //创造数据 private void initData() { for (int m=0;m<4;m++) { JiLou jiLou=new JiLou(); jiLou.setJiLouId(m); jiLou.setJiLouName("机楼"+m); jiLou.setPath(""); jiLou.setAddTime(new Date(System.currentTimeMillis())); List<JiLou.CaiJi> caiJiModels=new ArrayList<>(); for (int j = 0; j < 6; j++) { JiLou.CaiJi caiJiModel=new JiLou.CaiJi(); caiJiModel.setCaiJiId(j); caiJiModel.setCaiJiNumber(String.valueOf(j)); caiJiModel.setPath(""); caiJiModel.setAddTime(new Date(System.currentTimeMillis())); caiJiModels.add(caiJiModel); } jiLou.setCaiJiList(caiJiModels); jiLouModels.add(jiLou); } } }
Demo布局:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/white" tools:context=".Demo"> <ExpandableListView android:id="@+id/expandable_listView" android:layout_width="match_parent" android:layout_height="match_parent" android:text="Hello World!" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> </LinearLayout>
效果图:
19:56:52
这样一个简单能够自由对接的数据的二级树形列表实现了,但是这样远远不够,如果经常使用的话,就要考虑能不能封装成一个通用的类。这样以后使用起来就方便多了。后续我会把这个二级树形封装一下。以后还会介绍一下三级树形的实现以及三级树形菜单的封装。
这里放一个三级树形列表实现的效果图,后续会介绍一下如何实现: