Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ExpandableListView - keep selected child in a "pressed" state

I'm using an ExpandableListView in a left nav for a tablet screen.

When a user presses a child of a group in my expandable list, I'd like to keep the child in the pressed state so that the user knows for which child the right hand content is being shown for.

For a ListView, I was able to accomplish this effect with this line in the code:

getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);

and then applying this selector:

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

The "state_activiated" is true on the listView item after the listView item is pressed.

I was hoping this same technique would work for my expandableListView but it hasn't. I used:

getExpandableListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);

and then used the same selector above, but it doesn't work. I've also tried other states such as state_selected and state_checked and those don't work either.

The selector above correctly applies the pressed and not pressed state. It looks like however with an ExpandableListView, the state is not "activated" after pressing a child.

Any help is appreciated. Thanks!

like image 358
Scott Avatar asked Nov 29 '11 18:11

Scott


1 Answers

Do the following on ExpandableListView:

Step 1. Set choice mode to single (Can be done in xml as android:choiceMode = "singleChoice")

Step 2. Use a selector xml as background (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>

Step 3. Call expandableListView.setItemChecked(index,true) in onChildClick() callback.

index is a 0 based index of the child item calculated as follows

Group 1 [index = 0]

  • Child item 1
  • Child item 2
  • Child item 3 [index = 3]

Group 2 [index = 4]

  • Child item 1
  • Child item 2
  • Child item 3 [index = 7]

Group 3 [index = 8]

  • Child item 1
  • Child item 2
  • Child item 3 [index = 11]

If we have list headers as well, they would also account for index values.

Here is a working example:

@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;
}
like image 120
silvermouse Avatar answered Oct 25 '22 18:10

silvermouse