先看效果圖:
上圖是我們要實現的效果,那么現在我們開始着手去做,主要分為以下幾步:
一丶我們需要根據效果圖去思考該如何動手,從上圖分析看,我們可以用一個相對布局RelativeLayout來完成group(一級item)的布局設計,至於child(二級item)的布局,我們可以用一個TextView來完成,當然,如果如要更復雜的效果可以參照一級item的布局方式進行。
以下是main.xml丶group.xml和child.xml的布局:
main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<ExpandableListView
android:id="@+id/list"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#ffffff"
android:cacheColorHint="#00000000"
android:listSelector="#00000000"
>
</ExpandableListView>
</LinearLayout>
group.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/group_layout">
<ImageView
android:id="@+id/group_logo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_centerInParent="true"
android:layout_marginLeft="10dp"
android:contentDescription="@string/list_logo" />
<TextView
android:id="@+id/group_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_toRightOf="@id/group_logo"
android:textColor="#130c0e"
android:textSize="18sp" />
<TextView
android:id="@+id/group_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/group_title"
android:layout_marginLeft="10dp"
android:layout_toRightOf="@id/group_logo"
android:textColor="#838B8B"
android:textSize="15sp" />
<ImageView
android:id="@+id/group_state"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerInParent="true"
android:layout_marginRight="10dp"
android:contentDescription="@string/list_state" />
</RelativeLayout>
child.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView
android:id="@+id/child_text"
android:layout_width="wrap_content"
android:layout_height="20dp"
android:layout_centerInParent="true"
android:layout_marginTop="15dp"
android:textColor="#130c0e"
android:textSize="15sp" />
</RelativeLayout>
二、布局文件設置好以后,我們開始着手去實現代碼,首先談談我在實現過程中遇到的問題:
一:在剛開始為二級item(expandableListView.setOnChildClickListener)設置點擊事件時,自己思維進入了一個誤區,刷新代碼寫錯位置導致二級item不能實時表明選中狀態,實驗了一番發現自己腦子發抽,其實把代碼轉移到點擊事件中就OK了。
二:為一級item設置點擊事件時,剛開始想套用二級Item點擊事件的方法去做,發現行不通后,自己實驗了一番,定義了一個整型數組來存放對應groupPosition的點擊次數,根據點擊次數來設置狀態圖標,功能雖然實現了,但是感覺自己的這個方法不大實用,如果是動態加入就有點問題了,這個還希望各位看官給點建議。
好了,廢話不多說了,下面是實現的代碼,希望各位不吝指教:
/**
* 自定義ExpandableList列表類
*
* @author jgduan
*
*/
public class ExpandableList extends Activity {
// 這個數組是用來存儲一級item的點擊次數的,根據點擊次數設置一級標簽的選中、為選中狀態
private int[] group_checked = new int[]{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
// 用來標識是否設置二級item背景色為綠色,初始值為-1既為選中狀態
private int child_groupId = -1;
private int child_childId = -1;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 隱藏標題
requestWindowFeature(Window.FEATURE_NO_TITLE);
// 指定布局
setContentView(R.layout.main);
// 新建一個ExpandableListView
ExpandableListView expandableListView = (ExpandableListView) findViewById(R.id.list);
// 設置默認圖標為不顯示狀態
expandableListView.setGroupIndicator(null);
// 為列表綁定數據源
expandableListView.setAdapter(adapter);
// 設置一級item點擊的監聽器
expandableListView.setOnGroupClickListener(new OnGroupClickListener() {
@Override
public boolean onGroupClick(ExpandableListView parent, View v,
int groupPosition, long id) {
group_checked[groupPosition] = group_checked[groupPosition]+1;
// 刷新界面
((BaseExpandableListAdapter) adapter).notifyDataSetChanged();
return false;
}
});
// 設置二級item點擊的監聽器
expandableListView.setOnChildClickListener(new OnChildClickListener() {
@Override
public boolean onChildClick(ExpandableListView parent, View v,
int groupPosition, int childPosition, long id) {
// 將被點擊的一丶二級標簽的位置記錄下來
child_groupId = groupPosition;
child_childId = childPosition;
// 刷新界面
((BaseExpandableListAdapter) adapter).notifyDataSetChanged();
return false;
}
});
}
final ExpandableListAdapter adapter = new BaseExpandableListAdapter() {
// 一級標簽上的logo圖片數據源
int[] group_logo_array = new int[] { R.drawable.map,
R.drawable.message, R.drawable.music, R.drawable.children };
// 一級標簽上的標題數據源
private String[] group_title_arry = new String[] { "中醫常識", "中醫養生",
"美容養顏", "育兒百科" };
// 一級標簽的描述文本數據源
private String[] group_text_array = new String[] { "四診法、穴位、經絡等",
"葯膳食療,安神醒腦等", "減肥、明目等", "關注幼兒保健" };
// 子視圖顯示文字
private String[][] child_text_array = new String[][] {
{ "孕吐怎么辦", "新生兒黃疸的治療", "嬰兒吐奶怎么辦", "小兒感冒咳嗽怎么辦" },
{ "孕吐怎么辦", "新生兒黃疸的治療", "嬰兒吐奶怎么辦", "小兒感冒咳嗽怎么辦" },
{ "孕吐怎么辦", "新生兒黃疸的治療", "嬰兒吐奶怎么辦", "小兒感冒咳嗽怎么辦" },
{ "孕吐怎么辦", "新生兒黃疸的治療", "嬰兒吐奶怎么辦", "小兒感冒咳嗽怎么辦" } };
// 一級標簽上的狀態圖片數據源
int[] group_state_array = new int[] { R.drawable.group_down,
R.drawable.group_up };
// 重寫ExpandableListAdapter中的各個方法
/**
* 獲取一級標簽總數
*/
@Override
public int getGroupCount() {
return group_text_array.length;
}
/**
* 獲取一級標簽內容
*/
@Override
public Object getGroup(int groupPosition) {
return group_text_array[groupPosition];
}
/**
* 獲取一級標簽的ID
*/
@Override
public long getGroupId(int groupPosition) {
return groupPosition;
}
/**
* 獲取一級標簽下二級標簽的總數
*/
@Override
public int getChildrenCount(int groupPosition) {
return child_text_array[groupPosition].length;
}
/**
* 獲取一級標簽下二級標簽的內容
*/
@Override
public Object getChild(int groupPosition, int childPosition) {
return child_text_array[groupPosition][childPosition];
}
/**
* 獲取二級標簽的ID
*/
@Override
public long getChildId(int groupPosition, int childPosition) {
return childPosition;
}
/**
* 指定位置相應的組視圖
*/
@Override
public boolean hasStableIds() {
return true;
}
/**
* 對一級標簽進行設置
*/
@Override
public View getGroupView(int groupPosition, boolean isExpanded,
View convertView, ViewGroup parent) {
// 為視圖對象指定布局
convertView = (RelativeLayout) RelativeLayout.inflate(
getBaseContext(), R.layout.group, null);
/**
* 聲明視圖上要顯示的控件
*/
// 新建一個ImageView對象,用來顯示一級標簽上的logo圖片
ImageView group_logo = (ImageView) convertView
.findViewById(R.id.group_logo);
// 新建一個TextView對象,用來顯示一級標簽上的標題信息
TextView group_title = (TextView) convertView
.findViewById(R.id.group_title);
// 新建一個TextView對象,用來顯示一級標簽上的大體描述的信息
TextView group_text = (TextView) convertView
.findViewById(R.id.group_text);
// 新建一個ImageView對象,根據用戶點擊來標識一級標簽的選中狀態
ImageView group_state = (ImageView) convertView
.findViewById(R.id.group_state);
/**
* 設置相應控件的內容
*/
// 設置要顯示的圖片
group_logo.setBackgroundResource(group_logo_array[groupPosition]);
// 設置標題上的文本信息
group_title.setText(group_title_arry[groupPosition]);
// 設置整體描述上的文本信息
group_text.setText(group_text_array[groupPosition]);
if(group_checked[groupPosition] % 2 == 1){
// 設置默認的圖片是選中狀態
group_state.setBackgroundResource(group_state_array[1]);
}else{
for(int test : group_checked){
if(test == 0 || test % 2 == 0){
// 設置默認的圖片是未選中狀態
group_state.setBackgroundResource(group_state_array[0]);
}
}
}
// 返回一個布局對象
return convertView;
}
/**
* 對一級標簽下的二級標簽進行設置
*/
@Override
public View getChildView(int groupPosition, int childPosition,
boolean isLastChild, View convertView, ViewGroup parent) {
// 為視圖對象指定布局
convertView = (RelativeLayout) RelativeLayout.inflate(
getBaseContext(), R.layout.child, null);
/**
* 聲明視圖上要顯示的控件
*/
// 新建一個TextView對象,用來顯示具體內容
TextView child_text = (TextView) convertView
.findViewById(R.id.child_text);
/**
* 設置相應控件的內容
*/
// 設置要顯示的文本信息
child_text.setText(child_text_array[groupPosition][childPosition]);
// 判斷item的位置是否相同,如相同,則表示為選中狀態,更改其背景顏色,如不相同,則設置背景色為白色
if (child_groupId == groupPosition
&& child_childId == childPosition) {
// 設置背景色為綠色
convertView.setBackgroundColor(Color.GREEN);
} else {
// 設置背景色為白色
convertView.setBackgroundColor(Color.WHITE);
}
// 返回一個布局對象
return convertView;
}
/**
* 當選擇子節點的時候,調用該方法
*/
@Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
return true;
}
};
}
}