支持多項選擇的ExpandableListView
本文實例為大家分享了ExpandableListView多項選擇展示的具體代碼,供大家參考,具體內容如下
目標(需求):
1. 創(chuàng)建一個可展開可收縮的列表;
2. 其列表項包含多個checkable的部件,當選擇某一行時,該行包含的checkable的部件需要作出相應的變化;
3. 可以選擇多個列表項,并且這些列表項可被讀出
結果圖:

實現(xiàn):
1. 創(chuàng)建主layout用于規(guī)劃列表顯示。對于具體的列表項,為了實現(xiàn)的方便我們也創(chuàng)建一個layout文件。
<?xml version="1.0" encoding="utf-8"?> <com.home.mymultichecklistview.CheckableLinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/layout" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" > <com.home.mymultichecklistview.CheckableTextView android:id="@+id/item" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="6dip" style="@style/text" android:layout_weight="1" /> <com.home.mymultichecklistview.InertCheckBox android:id="@+id/checkbox" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginRight="5dp" android:maxWidth="40dp" android:maxHeight="40dp" android:focusable="false" android:layout_gravity="right" android:button="@drawable/checkbox" /> </com.home.mymultichecklistview.CheckableLinearLayout>
2. 類似ListView,ExpandableListView也是通過Adapter來管理其包含的各種元素和操作,這里我們創(chuàng)建一個擴展自BaseExpandableListAdapter的Adapter。與ListView不同的是,ExpandableListAdapter要渲染實現(xiàn)兩級View(Group級和列表項級)的操作。它通過getGroupView()渲染Group項,通過getChildView()渲染列表子項。
@Override
public View getGroupView(int groupPosition, boolean isExpanded,
View convertView, ViewGroup parent) {
View groupView = convertView;
if (groupView == null) {
groupView = new TextView(context);
((TextView)groupView).setGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL);
groupView.setPadding(50,0,0,0);
}
((TextView)groupView).setText(groupData[groupPosition]);
((TextView)groupView).setTextColor(context.getResources().getColor(R.color.fgcolor));
return groupView;
}
@Override
public View getChildView(final int groupPosition, final int childPosition,
boolean isLastChild, View convertView, ViewGroup parent) {
View itemView = convertView;
final ViewHolder vh;
if (itemView == null) {
LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
itemView = inflater.inflate(R.layout.item_view, null);
vh = new ViewHolder();
vh.layout = (CheckableLinearLayout)itemView.findViewById(R.id.layout);
vh.item = (TextView)itemView.findViewById(R.id.item);
itemView.setTag(vh);
} else {
vh = (ViewHolder)itemView.getTag();
}
vh.item.setText(itemData[groupPosition][childPosition]);
final ExpandableListView listView = ((ExpandableListView)((MainActivity)context).findViewById(R.id.list));
final int position = listView.getFlatListPosition(ExpandableListView.getPackedPositionForChild(groupPosition, childPosition));
listView.setItemChecked(position, checkedState[groupPosition][childPosition]);
vh.layout.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
((CheckableLinearLayout)v).toggle();
checkedState[groupPosition][childPosition] = !checkedState[groupPosition][childPosition];
listView.setItemChecked(position, ((CheckableLinearLayout)v).isChecked());
}
});
return itemView;
}
3. 為每一列表子項容器創(chuàng)建OnClickListener監(jiān)聽鼠標的點擊事件。在這里要注意,由于列表子項包含了CheckBox,所以為了使點擊事件不要被CheckBox捕獲,我們需要創(chuàng)建一個擴展自CheckBox的類來屏蔽鼠標和鍵盤事件。同時,需要在這個容器里搜索其包含的checkable的部件并將check操作傳給這些部件。
Adapter中的方法getChildView()需要實現(xiàn)鼠標點擊監(jiān)聽器:
public View getChildView(final int groupPosition, final int childPosition,
boolean isLastChild, View convertView, ViewGroup parent) {
View itemView = convertView;
final ViewHolder vh;
...
final int position = listView.getFlatListPosition(ExpandableListView.getPackedPositionForChild(groupPosition, childPosition));
listView.setItemChecked(position, checkedState[groupPosition][childPosition]);
vh.layout.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
((CheckableLinearLayout)v).toggle();
checkedState[groupPosition][childPosition] = !checkedState[groupPosition][childPosition];
listView.setItemChecked(position, ((CheckableLinearLayout)v).isChecked());
}
});
return itemView;
}
擴展自CheckBox的InertCheckBox需要屏蔽鍵盤和鼠標事件
public class InertCheckBox extends CheckBox {
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
//直接返回false
return false;
}
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
//直接返回false
return false;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
//直接返回false
return false;
}
@Override
public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) {
//直接返回false
return false;
...
}
列表項容器需要實現(xiàn)Checkable接口并且把check操作傳遞給其checkable的子部件
public class CheckableLinearLayout extends LinearLayout implements Checkable {
...
@Override
public void setChecked(boolean checked) {
this.isChecked = checked;
for (Checkable view : checkableViews) {
view.setChecked(checked);
}
}
@Override
public boolean isChecked() {
return this.isChecked;
}
@Override
public void toggle() {
isChecked = !isChecked;
for (Checkable view : checkableViews) {
view.toggle();
}
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
for (int i=0; i<this.getChildCount(); i++) {
findCheckableChild(this.getChildAt(i));
}
}
private void findCheckableChild(View child) {
if (child instanceof Checkable) {
checkableViews.add((Checkable)child);
}
if (child instanceof ViewGroup) {
for (int i=0; i<((ViewGroup)child).getChildCount(); i++) {
findCheckableChild(((ViewGroup) child).getChildAt(i));
}
}
}
...
}
開發(fā)中遇到的問題:
1. 渲染后的child view類似于放在一個cache中,下一次再通過convertView取時,由于Group的收縮或擴展操作會隱藏/顯示一些child view,導致某一child View的flat position發(fā)生變化,獲取到的convertView不是原來希望獲取的view。所以,每次獲取到view后都需要對其內容重新設置(比如設置正確文本,設置監(jiān)聽器等)
2. check的狀態(tài)設置很tricky。我開始認為直接在監(jiān)聽器中調用容器的toggle()方法即可。結果發(fā)現(xiàn)一旦某個group做了expand或collapse操作后,所有列表項的check狀態(tài)全沒了。后來發(fā)現(xiàn)原來group做了expand/collapse操作后,ListView會對其所有子項重新設置check狀態(tài),而check狀態(tài)的值是存在ListView的一個SparseBooleanArray表里(mCheckStates)。由于沒有對這個表進行設置,所以一刷新check狀態(tài)就全丟了。并且由于這個表的key是基于拉平后所有可見的列表項的位置定的,當group擴展或收縮后,同一個列表項,它拉平后的位置還會變化。所以,為了解決這個問題,我在adapter里增加了一個二維表用于記錄每一列表項的check狀態(tài)。在執(zhí)行 listView的setItemChecked函數(shù)時,其check狀態(tài)是從這個自己創(chuàng)建的表中讀出的,不能通過ListView的mCheckStates來讀。這個我認為是ExpandableListView的一個缺陷。
遺留的已知問題:
我使用了@drawable/checkbox 來定義checkbox check 和uncheck時的圖片,但當checkbox被check上時,這個checked的圖片沒有生效。不知道為什么,還需要進一步debug.
源程序:Multi-check-in-expandablelistview
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關文章
仿墨跡天氣在Android App中實現(xiàn)自定義zip皮膚更換
這篇文章主要介紹了仿墨跡天氣在Android App中實現(xiàn)自定義zip皮膚更換的方法,即讓用戶可以自行通過自制或者下載的zip皮膚包進行換膚,需要的朋友可以參考下2016-02-02
Android編程之Button控件配合Toast控件用法分析
這篇文章主要介紹了Android編程之Button控件配合Toast控件用法,結合實例形式分析了Button控件及Toast控件的功能及具體使用技巧,需要的朋友可以參考下2015-12-12
Android總結之WebView與Javascript交互(互相調用)
本篇文章主要介紹了WebView與Javascript進行數(shù)據交互,詳解的講訴了WebView與Javascript進行數(shù)據交互的方法,有興趣的可以了解一下。2016-11-11
android 獲取APP的唯一標識applicationId的實例
下面小編就為大家分享一篇android 獲取APP的唯一標識applicationId的實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-02-02

