前两天看到这篇文章:http://blog.163.com/zhj_mouse/blog/static/64118537201201222129974/,里面介绍了一种二级可展开列表,而且一级二级列表项都带一个CheckBox,可以任意勾选,觉得不错。不过,在这个程序中,点击二级列表项是勾选此项的CheckBox,点击CheckBox也是勾选CheckBox。我觉得,如果点击二级列表项即转到一个新的Activity中,点击CheckBox才勾选CheckBox,可能用途更广泛点。
在getGroupView中为每个CheckBox设置一个ClickListener,当有点击事件时,首先获取CheckBox的状态(代码2,选中为true,否则为false),然后把此状态保存进groupCheckBox中(代码3),groupCheckBox是一个List<Map<String, boolean>>变量。最后在代码4中通知列表刷新数据,然后列表控件会调用getGroupView为每个项更新状态/数据。
运行这个程序,发现每个二级列表只有当最后一项被选中了,前面项才能选中,而且选中第二个一级项时有时候会影响到第一个一级项里面的部分二级项。Debug了一下这段程序,发现代码1处根本得不到选中值(true),在程序界面上看是CheckBox被选中了,但马上又被反选了,看起来就是一个勾在CheckBox中飞快的闪了一下。所以这个办法不行。(只是不知道为什么在一级列表项中可以)
再分析了一下原程序,发现他对二级项的处理是在ListView的setOnChildClickListener中:
在这段程序中,并没有去试图用isChecked来获取CheckBox的状态,而是用一个boolean变量来保存CheckBox的状态,点击一次,反转一下这个变量的值,同时反转一下CheckBox的状态。这个boolean变量即保存在childCheckBox中。
于是,把这段程序结合到二级列表项的CheckBox的ClickListener中,如下:
运行,通过。此时,点击二级列表项不再选中该项的CheckBox。
最后,还要在解决当点击二级列表项时,进入一个新的Activity中。这个好办,有两种方法,可以在ListView的setOnChildClickListener中启动新的Activity,也可以在Adapter的getChildView方法中启动。如下:
方法一
当然,你要新建一个ChildActivity,并在AndroidManifest.xml文件中声明这个Activity。
首先,我注意到点击一级列表项是展开列表,点击一级列表项的CheckBox才是选中。所以二级列表项也可以参照一级列表项的代码。看一级列表项的构造代码getGroupView:
public View getGroupView(final int groupPosition, boolean isExpanded, View convertView, ViewGroup parent)
{
//此处省略部分代码 ...
gCheckBox.setChecked(groupCheckBox.get(groupPosition).get(G_CB));//…… 1
gCheckBox.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View v) {
Boolean isChecked = gCheckBox.isChecked();//…… 2
groupCheckBox.get(groupPosition).put(G_CB, isChecked);//…… 3
changChildStates(groupPosition, isChecked);
notifyDataSetChanged(); //…… 4
}
});
return v;
}
在getGroupView中为每个CheckBox设置一个ClickListener,当有点击事件时,首先获取CheckBox的状态(代码2,选中为true,否则为false),然后把此状态保存进groupCheckBox中(代码3),groupCheckBox是一个List<Map<String, boolean>>变量。最后在代码4中通知列表刷新数据,然后列表控件会调用getGroupView为每个项更新状态/数据。
按照这种思路,也为二级列表项的CheckBox设置一个ClickListener:
public View getChildView(final int groupPosition, final int childPosition, boolean isLastChild, View convertView, ViewGroup parent)
{
//此处省略部分代码 ...
holder.checkBox.setChecked(childCheckBox.get(groupPosition).get(childPosition).get(C_CB));
holder.checkBox.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View v)
{
Boolean isChecked = holder.checkBox.isChecked();//…… 1
childCheckBox.get(groupPosition).get(childPosition).put(C_CB, isChecked);
notifyDataSetChanged();
}
});
return convertView;
}
运行这个程序,发现每个二级列表只有当最后一项被选中了,前面项才能选中,而且选中第二个一级项时有时候会影响到第一个一级项里面的部分二级项。Debug了一下这段程序,发现代码1处根本得不到选中值(true),在程序界面上看是CheckBox被选中了,但马上又被反选了,看起来就是一个勾在CheckBox中飞快的闪了一下。所以这个办法不行。(只是不知道为什么在一级列表项中可以)
再分析了一下原程序,发现他对二级项的处理是在ListView的setOnChildClickListener中:
CheckBox checkBox = (CheckBox) v.findViewById(R.id.childCheckBox);
checkBox.toggle();
if (childCheckBox.get(groupPosition).get(childPosition).get(C_CB))
{
childCheckBox.get(groupPosition).get(childPosition).put(C_CB, false);
if (groupCheckBox.get(groupPosition).get(G_CB))
{
groupCheckBox.get(groupPosition).put(G_CB, false);
for (int i = 0; i < childCheckBox.get(groupPosition).size(); i++)
{
if (childPosition != i)
{
childCheckBox.get(groupPosition).get(i).put(C_CB, true);
}
}
}
}
else
{
int count = 0;
childCheckBox.get(groupPosition).get(childPosition).put(C_CB, true);
for (int i = 0; i < childCheckBox.get(groupPosition).size(); i++)
{
if (childCheckBox.get(groupPosition).get(i).get(C_CB))
{
count += 1;
}
}
if (count == childCheckBox.get(groupPosition).size())
{
groupCheckBox.get(groupPosition).put(G_CB, true);
}
}
adapter.notifyDataSetChanged();
在这段程序中,并没有去试图用isChecked来获取CheckBox的状态,而是用一个boolean变量来保存CheckBox的状态,点击一次,反转一下这个变量的值,同时反转一下CheckBox的状态。这个boolean变量即保存在childCheckBox中。
于是,把这段程序结合到二级列表项的CheckBox的ClickListener中,如下:
Boolean getCheckState = childCheckBox.get(groupPosition).get(childPosition).get(C_CB);
holder.checkBox.setChecked(getCheckState);
holder.checkBox.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View v)
{
if (childCheckBox.get(groupPosition).get(childPosition).get(C_CB))
{
childCheckBox.get(groupPosition).get(childPosition).put(C_CB, false);
if (groupCheckBox.get(groupPosition).get(G_CB))
{
groupCheckBox.get(groupPosition).put(G_CB, false);
for (int i = 0; i < childCheckBox.get(groupPosition).size(); i++)
{
if (childPosition != i)
{
String cname1 = childArray.get(groupPosition).get(i);
childCheckBox.get(groupPosition).get(i).put(C_CB, true);
}
}
}
}
else
{
int count = 0;
childCheckBox.get(groupPosition).
get(childPosition).put(C_CB, true);
for (int i = 0; i < childCheckBox.get(groupPosition).size(); i++)
{
if (childCheckBox.get(groupPosition).get(i).get(C_CB))
{
count += 1;
}
}
if (count == childCheckBox.get(groupPosition).size())
{
groupCheckBox.get(groupPosition).put(G_CB, true);
}
}
notifyDataSetChanged();
}
});
return convertView;
}
运行,通过。此时,点击二级列表项不再选中该项的CheckBox。
最后,还要在解决当点击二级列表项时,进入一个新的Activity中。这个好办,有两种方法,可以在ListView的setOnChildClickListener中启动新的Activity,也可以在Adapter的getChildView方法中启动。如下:
方法一
expandableListView.setOnChildClickListener(new OnChildClickListener()
{
@Override
public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id)
{
Intent intent = new Intent(MainActivity.this, ChildActivity.class);
startActivity(intent);
return false;
}
});
方法二
public View getChildView(final int groupPosition, final int childPosition, boolean isLastChild, View convertView, ViewGroup parent)
{
//省略部分代码...
convertView.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View v)
{
Intent intent = new Intent(context, ChildActivity.class);
context.startActivity(intent);
}
});
return convertView;
}
当然,你要新建一个ChildActivity,并在AndroidManifest.xml文件中声明这个Activity。