ExpandableList 跟 ListView 的實作觀念一樣
可以用 SimpleExpandableListAdapter 跟繼承 BaseExpandableListAdapter 的自訂 Adapter
由於 ExpandableList 有二層的資料
所以在 Adapter 要分別設定 Group 與 Child 的資料
實作是比較複雜一點
如果要在 ExpandableList 的 Group 及 Child 分別加上 CheckBox
而且 Group 的 CheckBox 跟 Child 的 CheckBox 互相關聯的話
在自訂 Adapter 就必須注意幾點
activity_main.xml
1
2
3
4
5
|
<
ExpandableListView
android:id
=
"@+id/listView"
android:layout_width
=
"match_parent"
android:layout_height
=
"wrap_content"
>
</
ExpandableListView
>
|
group_layout.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
<
TextView
android:id
=
"@+id/tvGroup"
android:layout_width
=
"280dp"
android:layout_height
=
"45dip"
android:gravity
=
"center_vertical|left"
android:paddingLeft
=
"45dp"
android:textSize
=
"17dip"
android:textStyle
=
"bold"
>
</
TextView
>
<
CheckBox
android:id
=
"@+id/chbGroup"
android:layout_width
=
"wrap_content"
android:layout_height
=
"wrap_content"
android:focusable
=
"false"
/>
|
group_layout.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
<
TextView
android:id
=
"@+id/tvChild"
android:layout_width
=
"280dp"
android:layout_height
=
"45dip"
android:gravity
=
"center_vertical"
android:paddingLeft
=
"45dp"
android:textSize
=
"17dip"
android:textStyle
=
"bold"
>
</
TextView
>
<
CheckBox
android:id
=
"@+id/chbChild"
android:layout_width
=
"wrap_content"
android:layout_height
=
"wrap_content"
android:focusable
=
"false"
/>
|
MainActivity.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
@Override
public
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
groups =
new
ArrayList<Group>();
getJSONObject();
listView = (ExpandableListView) findViewById(R.id.listView);
adapter =
new
EListAdapter(
this
, groups);
listView.setAdapter(adapter);
}
/** 解悉 JSON 字串 */
private
void
getJSONObject() {
String jsonStr =
"{'CommunityUsersResult':[{'CommunityUsersList':[{'fullname':'a111','userid':11,'username':'a1'}"
+
",{'fullname':'b222','userid':12,'username':'b2'}],'id':1,'title':'人事部'},{'CommunityUsersList':[{'fullname':"
+
"'c333','userid':13,'username':'c3'},{'fullname':'d444','userid':14,'username':'d4'},{'fullname':'e555','userid':"
+
"15,'username':'e5'}],'id':2,'title':'開發部'},{'CommunityUsersList':[],'id':3,'title':'業務部'}]}"
;
try
{
JSONObject CommunityUsersResultObj =
new
JSONObject(jsonStr);
JSONArray groupList = CommunityUsersResultObj.getJSONArray(
"CommunityUsersResult"
);
for
(
int
i =
0
; i < groupList.length(); i++) {
JSONObject groupObj = (JSONObject) groupList.get(i);
Group group =
new
Group(groupObj.getString(
"id"
), groupObj.getString(
"title"
));
JSONArray childrenList = groupObj.getJSONArray(
"CommunityUsersList"
);
for
(
int
j =
0
; j < childrenList.length(); j++) {
JSONObject childObj = (JSONObject) childrenList.get(j);
Child child =
new
Child(childObj.getString(
"userid"
), childObj.getString(
"fullname"
), childObj.getString(
"username"
));
group.addChildrenItem(child);
}
groups.add(group);
}
}
catch
(JSONException e) {
Log.d(
"allenj"
, e.toString());
}
}
|
EListAdapter.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
|
public
class
EListAdapter
extends
BaseExpandableListAdapter {
private
Context context;
private
ArrayList<Group> groups;
public
EListAdapter(Context context, ArrayList<Group> groups) {
this
.context = context;
this
.groups = groups;
}
public
Object getChild(
int
groupPosition,
int
childPosition) {
groups.get(groupPosition).getChildItem(childPosition);
return
null
;
}
public
long
getChildId(
int
groupPosition,
int
childPosition) {
return
childPosition;
}
public
int
getChildrenCount(
int
groupPosition) {
return
groups.get(groupPosition).getChildrenCount();
}
public
Object getGroup(
int
groupPosition) {
return
groups.get(groupPosition);
}
public
int
getGroupCount() {
return
groups.size();
}
public
long
getGroupId(
int
groupPosition) {
return
groupPosition;
}
public
boolean
hasStableIds() {
return
false
;
}
public
boolean
isChildSelectable(
int
groupPosition,
int
childPosition) {
return
false
;
}
/** 設定 Group 資料 */
public
View getGroupView(
int
groupPosition,
boolean
isExpanded, View convertView, ViewGroup parent) {
Group group = (Group) getGroup(groupPosition);
if
(convertView ==
null
) {
LayoutInflater infalInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = infalInflater.inflate(R.layout.group_layout,
null
);
}
TextView tv = (TextView) convertView.findViewById(R.id.tvGroup);
tv.setText(group.getTitle());
// 重新產生 CheckBox 時,將存起來的 isChecked 狀態重新設定
CheckBox checkBox = (CheckBox) convertView.findViewById(R.id.chbGroup);
checkBox.setChecked(group.getChecked());
// 點擊 CheckBox 時,將狀態存起來
checkBox.setOnClickListener(
new
Group_CheckBox_Click(Integer.valueOf(groupPosition)));
return
convertView;
}
/** 勾選 Group CheckBox 時,存 Group CheckBox 的狀態,以及改變 Child CheckBox 的狀態 */
class
Group_CheckBox_Click
implements
OnClickListener {
private
int
groupPosition;
Group_CheckBox_Click(
int
groupPosition) {
this
.groupPosition = groupPosition;
}
public
void
onClick(View v) {
groups.get(groupPosition).toggle();
// 將 Children 的 isChecked 全面設成跟 Group 一樣
int
childrenCount = groups.get(groupPosition).getChildrenCount();
boolean
groupIsChecked = groups.get(groupPosition).getChecked();
for
(
int
i =
0
; i < childrenCount; i++)
groups.get(groupPosition).getChildItem(i).setChecked(groupIsChecked);
// 注意,一定要通知 ExpandableListView 資料已經改變,ExpandableListView 會重新產生畫面
notifyDataSetChanged();
}
}
/** 設定 Children 資料 */
public
View getChildView(
int
groupPosition,
int
childPosition,
boolean
isLastChild, View convertView, ViewGroup parent) {
Child child = groups.get(groupPosition).getChildItem(childPosition);
if
(convertView ==
null
) {
LayoutInflater infalInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = infalInflater.inflate(R.layout.child_layout,
null
);
}
TextView tv = (TextView) convertView.findViewById(R.id.tvChild);
tv.setText(child.getFullname());
// 重新產生 CheckBox 時,將存起來的 isChecked 狀態重新設定
CheckBox checkBox = (CheckBox) convertView.findViewById(R.id.chbChild);
checkBox.setChecked(child.getChecked());
// 點擊 CheckBox 時,將狀態存起來
checkBox.setOnClickListener(
new
Child_CheckBox_Click(Integer.valueOf(groupPosition), Integer.valueOf(childPosition)));
return
convertView;
}
/** 勾選 Child CheckBox 時,存 Child CheckBox 的狀態 */
class
Child_CheckBox_Click
implements
OnClickListener {
private
int
groupPosition;
private
int
childPosition;
Child_CheckBox_Click(
int
groupPosition,
int
childPosition) {
this
.groupPosition = groupPosition;
this
.childPosition = childPosition;
}
public
void
onClick(View v) {
groups.get(groupPosition).getChildItem(childPosition).toggle();
// 檢查 Child CheckBox 是否有全部勾選,以控制 Group CheckBox
int
childrenCount = groups.get(groupPosition).getChildrenCount();
boolean
childrenAllIsChecked =
true
;
for
(
int
i =
0
; i < childrenCount; i++) {
if
(!groups.get(groupPosition).getChildItem(i).getChecked())
childrenAllIsChecked =
false
;
}
groups.get(groupPosition).setChecked(childrenAllIsChecked);
// 注意,一定要通知 ExpandableListView 資料已經改變,ExpandableListView 會重新產生畫面
notifyDataSetChanged();
}
}
}
|
Group.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
public
class
Group {
private
String id;
private
String title;
private
ArrayList<Child> children;
private
boolean
isChecked;
public
Group(String id, String title) {
this
.id = id;
this
.title = title;
children =
new
ArrayList<Child>();
this
.isChecked =
false
;
}
public
void
setChecked(
boolean
isChecked) {
this
.isChecked = isChecked;
}
public
void
toggle() {
this
.isChecked = !
this
.isChecked;
}
public
boolean
getChecked() {
return
this
.isChecked;
}
public
String getId() {
return
id;
}
public
String getTitle() {
return
title;
}
public
void
addChildrenItem(Child child) {
children.add(child);
}
public
int
getChildrenCount() {
return
children.size();
}
public
Child getChildItem(
int
index) {
return
children.get(index);
}
}
|
Group.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
public
class
Child {
private
String userid;
private
String fullname;
private
String username;
private
boolean
isChecked;
public
Child(String userid, String fullname, String username) {
this
.userid = userid;
this
.fullname = fullname;
this
.username = username;
this
.isChecked =
false
;
}
public
void
setChecked(
boolean
isChecked) {
this
.isChecked = isChecked;
}
public
void
toggle() {
this
.isChecked = !
this
.isChecked;
}
public
boolean
getChecked() {
return
this
.isChecked;
}
public
String getUserid() {
return
userid;
}
public
String getFullname() {
return
fullname;
}
public
String getUsername() {
return
username;
}
}
|
注意事項
SimpleExpandableListAdapter 呼叫 notifyDataSetChanged 函式時
是在 New 出一個 Adapter 時,用 adapter.notifyDataSetChanged()
不過自訂 Adapter 的話,要在自訂 Adapter 類別裡呼叫 notifyDataSetChanged() 即可
這一點筆者也是卡了很久