ExpandableListView – 保持选中的孩子处于“按下”状态

我在左侧导航栏中使用ExpandableListView来显示平板电脑屏幕。

当用户按下我的可扩展列表中的一个组的孩子时,我想让孩子保持按下状态,以便用户知道哪个孩子正在显示右手内容。

对于一个ListView,我可以用代码中的这一行来完成这个效果:

getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE); 

然后应用这个select器:

 <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项目被按下之后,listView项目上的“state_activiated”成立。

我希望这种技术可以为我的expandableListView工作,但它没有。 我用了:

 getExpandableListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE); 

然后使用上面相同的select器,但它不起作用。 我也尝试了其他状态,如state_selected和state_checked,这些也不起作用。

上面的select器正确地应用了按下和未按下的状态。 看起来像一个ExpandableListView,按下一个孩子后,状态不是“激活”的。

任何帮助表示赞赏。 谢谢!

Solutions Collecting From Web of "ExpandableListView – 保持选中的孩子处于“按下”状态"

在ExpandableListView上执行以下操作:

第1步。设置select模式为单(可以在xml中完成android:choiceMode =“singleChoice”

第2步。使用select器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步。在onChildClick()callback中调用expandableListView.setItemChecked( index,true)

索引是子项目的基于0的索引,计算如下

组1 [index = 0]

  • 子项目1
  • 儿童项目2
  • 子项目3 [index = 3]

第2组 [索引= 4]

  • 子项目1
  • 儿童项目2
  • 子项目3 [index = 7]

第3组 [索引= 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; } 

我最终解决了这个问题,而不是在子视图上使用select器。 expandableListView的适配器为每个组和子组获取数据。 我为子数据添加了一个“选定的”布尔值。 该片段负责正确设置每个孩子的select布尔值为true或false。 然后,在适配器的“getChildView”方法中,如果孩子的“selected”布尔值为true,我将视图的背景资源设置为“按下”背景。 否则,我将其设置为“未按下”的背景。 除了在子视图上使用textView的select器来更改文本颜色时,还可以实现所需的效果。

以下是我的片段保持孩子的“select”布尔值的事情:

  • 保持您的组/子数据作为您的片段中的类variables
  • onChildClick – 通过子数据循环,设置所有“选中”= false。 然后将当前组/子项的子项设置为true。 通过调用setEmptyView刷新expandableListView,重置侦听器并设置列表适配器。
  • onGroupClick – 通过子数据循环,设置所有“选中”= false。 然后将当前组/子项的子项设置为true。
  • 无论在哪里你的片段显示你的列表 – 填充你的适配器数据,设置列表适配器,调用适配器上的notifyDataSetChanged。 通过调用setEmptyView刷新expandableListView,重置侦听器并设置列表适配器。

除了上面的内容,我还将currentGroupPosition和currentChildPosition维护为类variables。 使用setRetainInstance = true允许这个在屏幕旋转之类的东西上正常工作。

我不认为有任何内置的方式来做你想要的内置Androidfunction。 为了做一些testing,我开始使用Android API示例中的代码( C:\<android-sdk-directory>\samples\android-15\ApiDemos\src\com\example\android\apis\view\ExpandableList3.java ) 。

我使用ExpandableListView.CHOICE_MODE_SINGLE 。 select模式适用于任何View被检查或select。 ( ExpandableListView源代码说它确定一次可以select多less个项目,但是在ListView ,它似乎适用于所检查的内容 。)另外请注意,文档说,您不能从getCheckedItemPosition获取ListView中的有效结果select模式。 这似乎是真的。

我的testing显示, 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里面,我做了一些testing,发现如下:

 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 */ 

我也尝试创build一个新的OnItemClickListener并实现其onItemClick方法。 虽然文档build议onItemClickListener将在ExpandableListView的某些function上工作,但我从来没有见过它。

我试图改变所select的子项目的背景颜色并保持突出显示的第一件事情并不奏效。 我在selector XML文件中为android:state_window_focused="true"设置了一个Drawable 。 它的工作有点,但提出了几个问题。

我尝试的第二件事是通过调用viewClicked.setSelected(true);显式selectonChildClick按下的项目viewClicked.setSelected(true); 。 这里的问题较less:

1)如果我滚动,直到突出显示的项目不在视图中,并且返回给它,突出显示消失,2)如果我旋转手机,也会发生同样的情况; 3)突出显示的项目状态不再被select因为它在显示屏上不再可见。

Android的ExpandableListView显然不是像手风琴风格的左侧导航菜单那样工作,尽pipe这似乎是一个相当明显的用途。 如果你想这样使用它,我认为你将不得不做大量的定制和挖掘如何绘制View

祝你好运。

全球声明:

 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")); } 

此解决scheme适用于我(导航视图中使用的可扩展列表视图):

例如,创build自定义菜单模型

 public class DrawerExpandedMenuModel { String iconName = ""; int id = -1; int iconImg = -1; boolean isSelected = false; . . . 

覆盖onChildClick的ExpandableListView

  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(); 

覆盖ExpandableListView的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)); 

而已!