我在平板电脑屏幕的左导航中使用了一个expandableelistview。
当用户按下可展开列表中组的子元素时,我想让子元素保持按下状态,以便用户知道哪个子元素显示了右手边的内容。
对于ListView,我可以用下面这行代码实现这个效果:
getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
,然后应用这个选择器:
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_activated="true" android:drawable="@drawable/menu_item_pressed" />
<item android:state_pressed="false" android:state_focused="false" android:drawable="@drawable/menu_item_normal" />
<item android:state_pressed="true" android:drawable="@drawable/menu_item_pressed" />
<item android:state_focused="true" android:state_pressed="false" android:drawable="@drawable/menu_item_pressed" />
按下listView后,state_activated在listView项上为true
我希望同样的技术将工作为我的可扩展elistview,但它没有。我使用:
getExpandableListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
,然后使用上面相同的选择器,但它不起作用。我还尝试了其他状态,如state_selected和state_checked,这些也不起作用。
上面的选择器正确地应用按下和未按下状态。它看起来像一个可扩展的elistview,状态不是"激活"后,按下一个子。
任何帮助都是感激的。谢谢!
在ExpandableListView上执行以下操作:
步骤1。设置选择模式为单一(可以在xml中完成android:choiceMode = " singlecchoice ")
步骤2。使用选择器xml作为背景(android:listSelector = "@drawable/selector_list_item")
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"
android:exitFadeDuration="@android:integer/config_mediumAnimTime">
<item android:drawable="@android:color/holo_blue_bright" android:state_pressed="true"/>
<item android:drawable="@android:color/holo_blue_light" android:state_selected="true"/>
<item android:drawable="@android:color/holo_blue_dark" android:state_activated="true"/>
</selector>
步骤3。调用 expandableelistview . setitemchecked (index,true)在onChildClick()回调中。
index是子条目的基于0的索引,计算如下
组1 [index = 0]
- 子项目1
- 子项目2
- 子条目3 [index = 3]
第二组 [index = 4]
- 子项目1
- 子项目2
- 子条目3 [index = 7]
第3组 [index = 8]
- 子项目1
- 子项目2
- 子条目3 [index = 11]
如果我们也有列表头,它们也会说明索引值。
下面是一个工作示例:
@Override
public boolean onChildClick(ExpandableListView parent, View v,
int groupPosition, int childPosition, long id) {
...
int index = parent.getFlatListPosition(ExpandableListView.getPackedPositionForChild(groupPosition, childPosition));
parent.setItemChecked(index, true);
return true;
}
我最终解决了这个问题,而没有在子视图上使用选择器。可扩展elistview的适配器获取每个组和子组的数据。我为子数据添加了一个"selected"布尔值。该片段负责将每个子节点的选定布尔值正确设置为true或false。然后,在适配器的"getChildView"方法中,如果子元素的"selected"布尔值为true,我将视图的背景资源设置为"pressed"背景。否则我将其设置为"未按下"背景。除了在子视图上使用textView的选择器来改变文本颜色外,这样做可以达到预期的效果。
下面是我的Fragment所做的事情来维护子节点的"selected"布尔值:
- 保持你的组/子数据作为一个类变量在你的片段
- onChildClick -循环遍历子数据,设置所有"selected"= false。然后将当前组/子的子设置为true。通过调用setEmptyView来刷新可扩展elistview,重置侦听器,并设置列表适配器。
- onGroupClick -循环遍历子数据,设置所有"selected"= false。然后将当前组/子的子设置为true。
- 无论在你的片段,你显示你的列表-填充你的适配器数据,设置列表适配器,调用notifyDataSetChanged上的适配器。通过调用setEmptyView来刷新可扩展elistview,重置侦听器,并设置列表适配器。
除了上面的,我维护一个currentGroupPosition和currentChildPosition作为类变量。使用setRetainInstance = true可以让它在屏幕旋转等情况下正常工作。
我不认为有任何内置的方法可以做到你所尝试的内置Android功能。为了做一些测试,我从Android API示例(C:<android-sdk-directory>samplesandroid-15ApiDemossrccomexampleandroidapisviewExpandableList3.java
)的代码开始。
我用的是ExpandableListView.CHOICE_MODE_SINGLE
。选择模式适用于选中或选中的View
。(ExpandableListView
源代码说,它决定有多少项可以选择一次,但在ListView
,它似乎适用于什么是检查。)还要注意的是,文件说,你不能得到一个有效的结果从getCheckedItemPosition
的ListView
在单一选择模式。这似乎是真的。
我的测试表明,ExpandableListActivity
不会自动使被点击/触摸的项目被选中或选中,也不会自动为被点击的子项目提供焦点。只有ExpandableListActivity
本身和持有子项目的组在单击它们的子项目之一后自动聚焦。
下面是我的一些代码(大部分来自Android的例子):
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
final String NAME = "NAME";
final String IS_EVEN = "IS_EVEN";
List<Map<String, String>> groupData = new ArrayList<Map<String, String>>();
List<List<Map<String, String>>> childData = new ArrayList<List<Map<String, String>>>();
for (int i = 0; i < 12; i++) {
Map<String, String> curGroupMap = new HashMap<String, String>();
groupData.add(curGroupMap);
curGroupMap.put(NAME, "Group " + i);
curGroupMap.put(IS_EVEN, (i % 2 == 0) ? "This group is even" : "This group is odd");
List<Map<String, String>> children = new ArrayList<Map<String, String>>();
for (int j = 0; j < 12; j++) {
Map<String, String> curChildMap = new HashMap<String, String>();
children.add(curChildMap);
curChildMap.put(NAME, "Child " + j);
curChildMap.put(IS_EVEN, (j % 2 == 0) ? "This child is even" : "This child is odd");
}
childData.add(children);
}
SimpleExpandableListAdapter adapter = new SimpleExpandableListAdapter(
this,
groupData,
android.R.layout.simple_expandable_list_item_1,
new String[] {NAME, IS_EVEN},
new int[] {android.R.id.text1, android.R.id.text2},
childData,
R.layout.child,
new String[] {NAME, IS_EVEN},
new int[] {android.R.id.text1, android.R.id.text2}
);
ExpandableListView expListView = (ExpandableListView)findViewById(android.R.id.list);
setListAdapter(adapter);
expListView.setChoiceMode(ExpandableListView.CHOICE_MODE_SINGLE);
expListView.setOnChildClickListener(new OnChildClickListener() {
@Override
public boolean onChildClick(ExpandableListView expListView, View viewClicked, int groupPosition, int childPosition, long childRowId) {
viewClicked.setSelected(true); // the only way to force a selection of the clicked item
注意最后一行,它强制被单击的子对象具有选定状态。然后,您可以使用带有Drawable
状态列表的XML selector
来突出显示选中的项目。(这并不能完全工作——后面会详细介绍)
在ExpandableListActivity
的onChildClick
里面,我做了一些测试,发现了以下内容:
groupPosition; // index of group within the ExpandableListViewActivity
childRowId; // for my particular ExpandableListView, this was the index of the child in the group
childPosition; // for my particularExpandableListView, this was also the index of the child in the group
expListView.getCheckedItemPosition(); // null - from ListView class
expListView.getSelectedView(); // null - from AbsListView class
expListView.getSelectedItemId(); // a long, based on the packed position - from AdapterView class
expListView.getSelectedId(); // -1 - from ExpandableListView class, calls getSelectedPosition()
expListView.getSelectedPosition(); // -1 - from ExpandableListView class, calls getSelectedItemPosition()
expListView.getSelectedItemPosition(); // -1 - from AdapterView class
expListView.getFocusedChild(); // null - from ViewGroup class
expListView.getItemIdAtPosition(1); // a long (View ID) - from AdapterView class
viewClicked.isFocused()); // false
viewClicked.isPressed()); // false
viewClicked.isSelected()); // true only if we explicitly set it to true
expListView.isFocused()); // true
expListView.isPressed()); // false
expListView.isSelected()); // false
expListView.getCheckedItemPosition())); // -1 - from ListView
expListView.getSelectedId())); // -1 - from ExpandableListView
/* expListView.getChildAt(childPosition) is not helpful, because it looks at the rendered
LinearLayout with a bunch of TextViews inside it to get the index and find the child,
and you won't generally know where to look for the child you want */
我还尝试创建一个新的OnItemClickListener
并实现其onItemClick
方法。尽管文档表明onItemClickListener
将在ExpandableListView
s上工作,但我从未见过它被称为。
第一件事,我试图改变所选择的子项目的背景颜色,并保持突出显示,没有很好地工作。我在selector
XML文件中为android:state_window_focused="true"
设置了Drawable
。它在一定程度上起了作用,但出现了几个问题。
我尝试的第二件事是通过调用viewClicked.setSelected(true);
显式地选择onChildClick
中按下的项目。这里的问题更少:
1)如果我滚动到高亮显示的项目从视图中消失,然后返回到它,高亮显示就消失了,2)如果我旋转手机,也会发生同样的情况,并且3)当高亮显示的项目在显示器上不再可见时,它的状态不再被选中。
Android的ExpandableListView
显然不打算像手风琴风格的左侧导航菜单一样工作,尽管这似乎是一个相当明显的用途。如果你想用这种方式使用它,我认为你必须做大量的自定义,并深入研究View
s是如何绘制的。
好运。
宣布全球:
View view_Group;
yourExpandableListView.setChoiceMode(ExpandableListView.CHOICE_MODE_SINGLE);
yourExpandableListView.setOnChildClickListener(new OnChildClickListener() {
@Override
public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) {
v.setSelected(true);
if (view_Group != null) {
view_Group.setBackgroundColor(Default Row Color Here);
}
view_Group = v;
view_Group.setBackgroundColor(Color.parseColor("#676767"));
}
这个解决方案适合我(可扩展的列表视图在导航视图中使用):
创建自定义菜单模型,例如
public class DrawerExpandedMenuModel {
String iconName = "";
int id = -1;
int iconImg = -1;
boolean isSelected = false;
.
.
.
覆盖expandableelistview的onChildClick
expandableList.setOnChildClickListener(new ExpandableListView.OnChildClickListener() {
@Override
public boolean onChildClick(ExpandableListView expandableListView, View view, int groupPosition, int childPosition, long l) {
for (int k = 0; k < listDataHeader.size(); k++){
listDataHeader.get(k).isSelected(false);
if (listDataChild.containsKey(listDataHeader.get(k))) {
List<DrawerExpandedMenuModel> childList = listDataChild.get(listDataHeader.get(k));
if (childList != null) {
for (int j = 0; j < childList.size(); j++) {
if (k == groupPosition && j == childPosition) {
childList.get(j).isSelected(true);
} else {
childList.get(j).isSelected(false);
}
}
}
}
}
mMenuAdapter.notifyDataSetChanged();
覆盖expandableelistview的onGroupClick
expandableList.setOnGroupClickListener(new ExpandableListView.OnGroupClickListener() {
@Override
public boolean onGroupClick(ExpandableListView expandableListView, View view, int groupPosition, long l) {
for (int k = 0; k < listDataHeader.size(); k++){
if (k == groupPosition) {
listDataHeader.get(k).isSelected(true);
} else {
listDataHeader.get(k).isSelected(false);
}
if (listDataChild.containsKey(listDataHeader.get(k))) {
List<DrawerExpandedMenuModel> childList = listDataChild.get(listDataHeader.get(k));
if (childList != null) {
for (int j = 0; j < childList.size(); j++) {
childList.get(j).isSelected(false);
}
}
}
}
mMenuAdapter.notifyDataSetChanged();
重写getGroupView和getChildView
public class DrawerExpandableListAdapter extends BaseExpandableListAdapter {
.
.
.
@Override
public View getGroupView(final int groupPosition, final boolean isExpanded, View convertView, final ViewGroup parent) {
if (headerTitle.isSelected() == true) convertView.setBackgroundColor(mContext.getResources().getColor(R.color.gray));
else convertView.setBackgroundColor(mContext.getResources().getColor(R.color.transparent));
.
.
.
@Override
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
if (childObj.isSelected() == true) convertView.setBackgroundColor(mContext.getResources().getColor(R.color.gray));
else convertView.setBackgroundColor(mContext.getResources().getColor(R.color.transparent));
就是这样!