ExpandableListView - 将选定的子项保持为“已按下”状态

时间:2011-11-29 18:33:02

标签: android android-widget

我在左侧导航中使用ExpandableListView作为平板电脑屏幕。

当用户在我的可扩展列表中按下某个组的子项时,我希望将该子项保持在按下状态,以便用户知道正在为哪个孩子显示右手内容。

对于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项后,listView项上的“state_activiated”为真。

我希望这种技术对我的expandableListView有效,但事实并非如此。我用过:

getExpandableListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);

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

上面的选择器正确地应用了按下和未按下状态。看起来使用ExpandableListView时,按下孩子后状态不会被“激活”。

感谢任何帮助。谢谢!

5 个答案:

答案 0 :(得分:33)

在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 :(得分:8)

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

以下是我的Fragment维护孩子的“选定”布尔值所做的事情:

  • 将您的组/子数据保存为片段中的类变量
  • onChildClick - 遍历子数据,设置所有“selected”= false。然后将当前组/子项的子项设置为true。通过调用setEmptyView刷新expandableListView,重置监听器,并设置列表适配器。
  • onGroupClick - 遍历子数据,设置所有“selected”= false。然后将当前组/子项的子项设置为true。
  • 在您的片段中显示列表的位置 - 填充适配器数据,设置列表适配器,在适配器上调用notifyDataSetChanged。通过调用setEmptyView刷新expandableListView,重置监听器,并设置列表适配器。

除了上面的内容,我还将currentGroupPosition和currentChildPosition维护为类变量。使用setRetainInstance = true可以在屏幕旋转等方面正常工作。

答案 2 :(得分:5)

我认为没有任何内置方法可以使用内置Android功能进行尝试。为了进行一些测试,我开始使用Android API示例(C:\<android-sdk-directory>\samples\android-15\ApiDemos\src\com\example\android\apis\view\ExpandableList3.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      

请注意最后一行,它会强制单击的子项具有选定状态。然后,您可以使用带有selector状态列表的XML Drawable来突出显示所选项目。 (这不完全有效 - 更多内容如下。)

在我onChildClick的{​​{1}}内,我做了一些测试,发现了以下内容:

ExpandableListActivity

我还尝试创建新的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方法。虽然文档表明onItemClickonItemClickListener上会以某种身份运行,但我从未见过它。

我尝试更改所选子项目的背景颜色并使其突出显示的第一件事并不能正常工作。我在ExpandableListView XML文件中为Drawable设置了android:state_window_focused="true"。它有点工作,但提出了几个问题。

我尝试的第二件事是通过调用selector明确选择onChildClick中按下的项目。这里的问题较少:

1)如果我滚动直到突出显示的项目不在视图中并返回到它,突出显示已消失,2)如果我旋转手机会发生同样的情况,3)突出显示的项目的状态不再在显示屏上不再显示时选择。

Android的viewClicked.setSelected(true);显然不是像手风琴式的左导航菜单一样工作,尽管这似乎是一个相当明显的用途。如果你想以这种方式使用它,我认为你必须进行大量的自定义并深入研究如何绘制ExpandableListView

祝你好运。

答案 3 :(得分:3)

全球宣布:

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

答案 4 :(得分:1)

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

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

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

就是这样!