可扩展列表视图 - 使选定的子项保持"pressed"状态



我在平板电脑屏幕的左导航中使用了一个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,它似乎适用于什么是检查。)还要注意的是,文件说,你不能得到一个有效的结果从getCheckedItemPositionListView在单一选择模式。这似乎是真的。

我的测试表明,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来突出显示选中的项目。(这并不能完全工作——后面会详细介绍)

ExpandableListActivityonChildClick里面,我做了一些测试,发现了以下内容:

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

就是这样!