BaseExpandableListAdapter,二級列表的完全自定義(一)
阿新 • • 發佈:2019-01-31
普通的ListView已經無法滿足需要,下面來詳細說明如何使用二級列表,二級列表有很多地方會使用到,如常見的QQ好友分組,效果圖如下:
具體的內容包括表頭和表體,點選表頭會展開或合併表體,為方便表示,表頭和表體均為圖片加文字的佈局。
分析完成二級列表需要的一些東西:
一:控制元件名稱 ExpandableListView
二:介面卡 繼承自BaseExpandableListAdapter
三:資料來源 以IT工作為例,把每組看成一個Object,所以資料來源為List<Work>
四:子佈局 包括表頭和表體
下面完成每項的具體程式碼:
表頭佈局 work_groups,包括圖片,表頭名,指示器(有預設的指示器,但不同版本和手機表現不一)
表體佈局 work_childs,包括圖片和表體名<?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="match_parent" android:orientation="horizontal" android:paddingBottom="5dp" android:paddingLeft="10dp" android:paddingRight="5dp" android:paddingTop="5dp" > <ImageView android:id="@+id/group_image1" android:layout_width="35dp" android:layout_height="35dp" android:layout_gravity="center_vertical" /> <TextView android:id="@+id/group_title" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_weight="1" android:gravity="center" android:textColor="#9A32CD" android:textSize="18sp" /> <ImageView android:id="@+id/group_image2" android:layout_width="30dp" android:layout_height="30dp" android:layout_gravity="center_vertical" /> </LinearLayout>
資料來源類 Work<?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="match_parent" android:orientation="horizontal" android:paddingBottom="5dp" android:paddingLeft="20dp" android:paddingRight="5dp" android:paddingTop="5dp" > <ImageView android:id="@+id/child_image1" android:layout_width="30dp" android:layout_height="30dp" android:layout_gravity="center_vertical" /> <TextView android:id="@+id/child_title" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_weight="1" android:gravity="center" android:textColor="#9A32CD" android:textSize="15sp" /> </LinearLayout>
public class Work {
private WorkGroup mWorkGroup;
private List<WorkChild> mWorkChildList;
public WorkGroup getmWorkGroup() {
return mWorkGroup;
}
public void setmWorkGroup(WorkGroup mWorkGroup) {
this.mWorkGroup = mWorkGroup;
}
public List<WorkChild> getmWorkChildList() {
return mWorkChildList;
}
public void setmWorkChildList(List<WorkChild> mWorkChildList) {
this.mWorkChildList = mWorkChildList;
}
}
WorkGroup
public class WorkGroup {
private int image1Group;// 圖片
private String titleGroup;// 表頭名
public int getImage1Group() {
return image1Group;
}
public void setImage1Group(int image1Group) {
this.image1Group = image1Group;
}
public String getTitleGroup() {
return titleGroup;
}
public void setTitleGroup(String titleGroup) {
this.titleGroup = titleGroup;
}
}
WorkChild
public class WorkChild {
private int imageChild;// 圖片
private String titleChild;// 表體名
public int getImageChild() {
return imageChild;
}
public void setImageChild(int imageChild) {
this.imageChild = imageChild;
}
public String getTitleChild() {
return titleChild;
}
public void setTitleChild(String titleChild) {
this.titleChild = titleChild;
}
}
下面是MyWorkAdapter,包括表頭和表體View的填充
public class MyWorkAdapter extends BaseExpandableListAdapter {
private List<Work> mList;
private LayoutInflater mLayoutInflater;
public MyWorkAdapter(Context context, List<Work> list) {
mLayoutInflater = LayoutInflater.from(context);
mList = list;
}
class GroupViewHolder {
// Group內部類快取
ImageView groupImage;
TextView groupTitle;
ImageView groupIndicator;
}
class ChildViewHolder {
// Child內部類快取
ImageView childImage;
TextView childTitle;
}
@Override
public int getGroupCount() {
// 返回表頭的數量,即List<Work>的長度
return mList.size();
}
@Override
public int getChildrenCount(int groupPosition) {
// 返回當前組內有表體數量,即每一組中List<WorkChild>的長度
return mList.get(groupPosition)// 得到當前的組Work
.getmWorkChildList().size();// 得到List<WorkChild>的長度
}
@Override
public Object getGroup(int groupPosition) {
// 返回當前組的表頭,即WorkGroup
return mList.get(groupPosition)// 得到當前的組Work
.getmWorkGroup();// 得到WorkGroup
}
@Override
public Object getChild(int groupPosition, int childPosition) {
// 返回當前組的當前表體項,即WorkChild
return mList.get(groupPosition)// 得到當前的組Work
.getmWorkChildList()// 得到List<WorkChild>
.get(childPosition);// 得到WorkChild
}
@Override
public long getGroupId(int groupPosition) {
// 返回當前表頭Id
return groupPosition;
}
@Override
public long getChildId(int groupPosition, int childPosition) {
// 返回當前表體Id
return childPosition;
}
@Override
public View getGroupView(int groupPosition, boolean isExpanded,
View convertView, ViewGroup parent) {
// 返回表頭View
GroupViewHolder mGroupViewHolder = null;
if (convertView == null) {
mGroupViewHolder = new GroupViewHolder();
// 內部類繫結相應控制元件
convertView = mLayoutInflater.inflate(R.layout.work_groups, parent,
false);
mGroupViewHolder.groupImage = (ImageView) convertView
.findViewById(R.id.group_image1);
mGroupViewHolder.groupTitle = (TextView) convertView
.findViewById(R.id.group_title);
mGroupViewHolder.groupIndicator = (ImageView) convertView
.findViewById(R.id.group_image2);
// 內部類綁定當前載入的convertView
convertView.setTag(mGroupViewHolder);
} else {
mGroupViewHolder = (GroupViewHolder) convertView.getTag();
}
// 當前convertView的資料來源WorkGroup
WorkGroup mWorkGroup = (WorkGroup) getGroup(groupPosition);
// 設定控制元件資源
mGroupViewHolder.groupImage.setBackgroundResource(mWorkGroup
.getImage1Group());
mGroupViewHolder.groupTitle.setText(mWorkGroup.getTitleGroup());
// 表頭的open和close設定不同image
if (isExpanded) {
mGroupViewHolder.groupIndicator
.setBackgroundResource(R.drawable.work_open);
} else {
mGroupViewHolder.groupIndicator
.setBackgroundResource(R.drawable.work_close);
}
return convertView;
}
@Override
public View getChildView(int groupPosition, int childPosition,
boolean isLastChild, View convertView, ViewGroup parent) {
// 返回表體View,具體內容同getGroupView一樣
ChildViewHolder mChildViewHolder = null;
if (convertView == null) {
mChildViewHolder = new ChildViewHolder();
// 內部類繫結相應控制元件
convertView = mLayoutInflater.inflate(R.layout.work_childs, parent,
false);
mChildViewHolder.childImage = (ImageView) convertView
.findViewById(R.id.child_image1);
mChildViewHolder.childTitle = (TextView) convertView
.findViewById(R.id.child_title);
// 內部類綁定當前載入的convertView
convertView.setTag(mChildViewHolder);
} else {
mChildViewHolder = (ChildViewHolder) convertView.getTag();
}
// 當前convertView的資料來源WorkChild
WorkChild mWorkChild = (WorkChild) getChild(groupPosition,
childPosition);
// 設定控制元件資源
mChildViewHolder.childImage.setBackgroundResource(mWorkChild
.getImageChild());
mChildViewHolder.childTitle.setText(mWorkChild.getTitleChild());
return convertView;
}
@Override
public boolean hasStableIds() {
// 是否指定分組檢視及其子檢視的Id對應的後臺資料改變也會保持該Id
return true;
}
@Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
// 指定位置的子檢視是否可選擇
return true;
}
}
接下來在Activity中初始化二級列表
主佈局 work_main
<?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="match_parent"
android:background="#C9C9C9"
android:orientation="vertical"
android:paddingTop="20dp" >
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="10dp"
android:text="技術"
android:textColor="#EE0000"
android:textSize="20sp" />
<ExpandableListView
android:id="@+id/list_1"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
ITWorkActivity
public class ITWorkActivity extends Activity {
private ExpandableListView mExpandableListView;
private MyWorkAdapter mMyWorkAdapter;
// 資料來源
private List<Work> mWorkList;
private Work mWork;
private WorkGroup mWorkGroup;
private List<WorkChild> mWorkChildList;
private WorkChild mWorkChild;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.work_main);
// 初始化資料
init();
mExpandableListView = (ExpandableListView) findViewById(R.id.list_1);
// 去除預設的指示器
mExpandableListView.setGroupIndicator(null);
mMyWorkAdapter = new MyWorkAdapter(getApplicationContext(), mWorkList);
mExpandableListView.setAdapter(mMyWorkAdapter);
}
private void init() {
mWorkList = new ArrayList<Work>();
// 後端開發
mWork = new Work();
// 表頭
mWorkGroup = new WorkGroup();
mWorkGroup.setImage1Group(R.drawable.life_logo);
mWorkGroup.setTitleGroup("後端開發");
mWork.setmWorkGroup(mWorkGroup);
// 表體
mWorkChildList = new ArrayList<WorkChild>();
mWorkChild = new WorkChild();// Java
mWorkChild.setImageChild(R.drawable.life_logo);
mWorkChild.setTitleChild("Java");
mWorkChildList.add(mWorkChild);
mWorkChild = new WorkChild();// PHP
mWorkChild.setImageChild(R.drawable.life_logo);
mWorkChild.setTitleChild("PHP");
mWorkChildList.add(mWorkChild);
mWorkChild = new WorkChild();// Python
mWorkChild.setImageChild(R.drawable.life_logo);
mWorkChild.setTitleChild("Python");
mWorkChildList.add(mWorkChild);
mWorkChild = new WorkChild();// C#
mWorkChild.setImageChild(R.drawable.life_logo);
mWorkChild.setTitleChild("C#");
mWorkChildList.add(mWorkChild);
mWorkChild = new WorkChild();// C++
mWorkChild.setImageChild(R.drawable.life_logo);
mWorkChild.setTitleChild("C++");
mWorkChildList.add(mWorkChild);
mWorkChild = new WorkChild();// C
mWorkChild.setImageChild(R.drawable.life_logo);
mWorkChild.setTitleChild("C");
mWorkChildList.add(mWorkChild);
mWorkChild = new WorkChild();// 後端開發其他
mWorkChild.setImageChild(R.drawable.life_logo);
mWorkChild.setTitleChild("後端開發其他");
mWorkChildList.add(mWorkChild);
mWork.setmWorkChildList(mWorkChildList);
mWorkList.add(mWork);
// 移動開發
mWork = new Work();
mWorkGroup = new WorkGroup();
mWorkGroup.setImage1Group(R.drawable.life_logo);
mWorkGroup.setTitleGroup("移動開發");
mWork.setmWorkGroup(mWorkGroup);
mWorkChildList = new ArrayList<WorkChild>();
mWorkChild = new WorkChild();// IOS
mWorkChild.setImageChild(R.drawable.life_logo);
mWorkChild.setTitleChild("IOS");
mWorkChildList.add(mWorkChild);
mWorkChild = new WorkChild();// Android
mWorkChild.setImageChild(R.drawable.life_logo);
mWorkChild.setTitleChild("Android");
mWorkChildList.add(mWorkChild);
mWorkChild = new WorkChild();// WP
mWorkChild.setImageChild(R.drawable.life_logo);
mWorkChild.setTitleChild("WP");
mWorkChildList.add(mWorkChild);
mWorkChild = new WorkChild();// 移動開發其他
mWorkChild.setImageChild(R.drawable.life_logo);
mWorkChild.setTitleChild("移動開發其他");
mWorkChildList.add(mWorkChild);
mWork.setmWorkChildList(mWorkChildList);
mWorkList.add(mWork);
}
}
最終成品圖如下:
到此一個完全自定義的靜態二級列表就完全OK了,但僅僅是展示內容是遠遠不夠的,在BaseExpandableListAdapter,二級列表的完全自定義(二)
中會實現二級列表的各種手勢和點選事件,預設展開項,速滑事件,表體點選事件,表頭和表體的長按事件,比如刪除分組名,新增分組等等。
好了,這章到此結束,有什麼錯誤或能優化的地方懇請多提意見和建議。