本文实例为大家分享了ExpandableListView多项选择展示的具体代码,供大家参考,具体内容如下
目标(需求):
1. 创建一个可展开可收缩的列表;
2. 其列表项包含多个checkable的部件,当选择某一行时,该行包含的checkable的部件需要作出相应的变化;
3. 可以选择多个列表项,并且这些列表项可被读出
结果图:
实现:
1. 创建主layout用于规划列表显示。对于具体的列表项,为了实现的方便我们也创建一个layout文件。
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
|
<? 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来管理其包含的各种元素和操作,这里我们创建一个扩展自BaseExpandableListAdapter的Adapter。与ListView不同的是,ExpandableListAdapter要渲染实现两级View(Group级和列表项级)的操作。它通过getGroupView()渲染Group项,通过getChildView()渲染列表子项。
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
|
@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. 为每一列表子项容器创建OnClickListener监听鼠标的点击事件。在这里要注意,由于列表子项包含了CheckBox,所以为了使点击事件不要被CheckBox捕获,我们需要创建一个扩展自CheckBox的类来屏蔽鼠标和键盘事件。同时,需要在这个容器里搜索其包含的checkable的部件并将check操作传给这些部件。
Adapter中的方法getChildView()需要实现鼠标点击监听器:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
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需要屏蔽键盘和鼠标事件
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
|
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 ;
...
}
|
列表项容器需要实现Checkable接口并且把check操作传递给其checkable的子部件
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 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));
}
}
}
...
}
|
开发中遇到的问题:
1. 渲染后的child view类似于放在一个cache中,下一次再通过convertView取时,由于Group的收缩或扩展操作会隐藏/显示一些child view,导致某一child View的flat position发生变化,获取到的convertView不是原来希望获取的view。所以,每次获取到view后都需要对其内容重新设置(比如设置正确文本,设置监听器等)
2. check的状态设置很tricky。我开始认为直接在监听器中调用容器的toggle()方法即可。结果发现一旦某个group做了expand或collapse操作后,所有列表项的check状态全没了。后来发现原来group做了expand/collapse操作后,ListView会对其所有子项重新设置check状态,而check状态的值是存在ListView的一个SparseBooleanArray表里(mCheckStates)。由于没有对这个表进行设置,所以一刷新check状态就全丢了。并且由于这个表的key是基于拉平后所有可见的列表项的位置定的,当group扩展或收缩后,同一个列表项,它拉平后的位置还会变化。所以,为了解决这个问题,我在adapter里增加了一个二维表用于记录每一列表项的check状态。在执行 listView的setItemChecked函数时,其check状态是从这个自己创建的表中读出的,不能通过ListView的mCheckStates来读。这个我认为是ExpandableListView的一个缺陷。
遗留的已知问题:
我使用了@drawable/checkbox 来定义checkbox check 和uncheck时的图片,但当checkbox被check上时,这个checked的图片没有生效。不知道为什么,还需要进一步debug.
源程序:Multi-check-in-expandablelistview
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。
原文链接:https://blog.csdn.net/swingseagull/article/details/17462405