可扩展列表视图 - 保持选中的子项处于“按下”状态

18

我正在使用可扩展列表视图在平板屏幕的左导航中。

当用户按下可扩展列表中的组中的子项时,我想保持子项处于按下状态,以便用户知道右侧内容显示的是哪个子项。

对于 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”会在该条目上变为true。

我原本希望这个技巧也适用于我的expandableListView,但事实证明并不行。我尝试使用:

getExpandableListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);

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

上面的选择器正确地应用了按下和未按下状态。但是在可扩展列表视图(ExpandableListView)中,似乎在按下子项后状态没有被“激活”。

任何帮助都将不胜感激。谢谢!


以下是我的回答有帮助吗?您为什么没有将其标记为已接受的答案呢? - hotshot309
是的,非常有用,谢谢(抱歉我忘了点赞)。 我将暂时搁置将其标记为已接受的答案,以防有人分享实现我寻找的效果的自制方法。 再次感谢! - Scott
5个回答

35

在ExpandableListView上执行以下操作:

步骤1。 将选择模式设置为单个(可以在xml中完成,如android:choiceMode =“singleChoice”

步骤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:在 onChildClick() 回调中调用 expandableListView.setItemChecked(index,true)

index 是按如下计算的子项 0 基础索引:

组1 [index = 0]

  • 子项1
  • 子项2
  • 子项3 [index = 3]

组2 [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;
}

1
如果你折叠了包含所选项的组并打开另一个组,似乎会出现一些奇怪的结果。 - Kevin DiTraglia
单层可展开列表视图运行良好,那么多层可展开列表视图呢? - Karthik
在选择另一个组中的项目时,其他组的项目也会被选中。 - Ashish Pandey

9
我最终解决了这个问题,而不是在子视图上使用选择器。ExpandableListView的适配器需要为每个组和子项提供数据。我添加了一个“selected”布尔值来表示子项数据。片段负责正确设置每个子项的选中布尔值true或false。然后,在适配器的“getChildView”方法中,如果子项的“selected”布尔值为true,则将视图的背景资源设置为我的“pressed”背景。否则,将其设置为“not pressed”背景。除此之外,还可以在子视图上使用选择器更改textView在按下时的文本颜色以实现所需效果。
以下是我要做的事情,以保持子项的“selected”布尔值:
- 将您的组/子项数据作为类变量保存在片段中 - onChildClick - 循环遍历子项数据,将所有“selected”= false。然后将当前组/子项的子项设置为true。通过调用setEmptyView,重置监听器并设置列表适配器来刷新expandableListView。 - onGroupClick - 循环遍历子项数据,将所有“selected”= false。然后将当前组/子项的子项设置为true。 - 在您的片段中显示列表的任何地方 - 填充您的适配器数据,设置列表适配器,调用适配器上的notifyDataSetChanged。通过调用setEmptyView,重置监听器并设置列表适配器来刷新expandableListView。
除了上述操作之外,我还将currentGroupPosition和currentChildPosition作为类变量进行了维护。使用setRetainInstance = true可以使其在诸如屏幕旋转等情况下正常工作。

我认为调用notifyDataSetChanged就足够了... 你为什么需要通过调用setEmptyView来刷新视图呢? - Giulio Piancastelli

5
我认为没有内置的方式可以使用内置的Android功能来实现您所尝试的内容。为了进行一些测试,我从Android API示例代码中开始(C:<android-sdk-directory>\samples\android-15\ApiDemos\src\com\example\android\apis\view\ExpandableList3.java)。
我使用了ExpandableListView.CHOICE_MODE_SINGLE。选择模式适用于所选的任何

2
需要多少个Android开发团队工程师来换灯泡?没有,因为他们决定不支持更换灯泡,所以你必须自己更换。 - Giulio Piancastelli

4

全局声明:

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

1
This solution works for me (expandable list view used inside navigation view):
创建自定义菜单模型,例如:
public class DrawerExpandedMenuModel {

String iconName = "";
int id = -1;
int iconImg = -1;
boolean isSelected = false;
.
.
.

重写ExpandableListView的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();

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

就是这样!


我认为这是一个更好的解决方案,在尝试了其他不同的方案之后。谢谢。 - praveenb

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接