Java – ExpandableListView opens the folding problem

ExpandableListView opens the folding problem… here is a solution to the problem.

ExpandableListView opens the folding problem

I’m using a custom extensible list adapter. When the user clicks on it, I highlight a child. This works fine until the user opens/collapses the group. Suppose the user touches Group 2 Item 1. This highlights Group 2 Item 1. The user then opens Group 1. Group 3 Item 2 is now highlighted. I’ve done some testing to select different items, but I can’t find the pattern that the highlighted line will jump to. Sometimes it’s in the list, sometimes it’s in the list. I can’t figure out the logic that put onGroupExpandListener and onGroupCollapseListener into the activity to re-highlight the correct View. Any ideas?

Edit: Current code in my onChildClickListener

if (groupPosition == 0){ 
      switch(childPosition) {
      case 0: 
        previouslySelectedView.setBackgroundResource(R.color.transparent);
        currentlySelectedView.setBackgroundResource(R.color.blue); 
        break;

The code is the same for all groups/children

Solution

Item selection in the ExpandableListView is made through a flat list (absolute positioning). Therefore, if the newly opened group is before the current network selection and has fewer children, the selection will move upwards and vice versa. I recommend setting the selection mode to None and implementing onclick/expand logic to handle your own focus – for example, implementing a label for View and setting the currently highlighted item by label.

Here are a few suggestions:

  1. In ExpandableListView.OnChildClickListener, you first execute ExpandableListView.findViewWithTag(theTag) to inspect Views with such tags and unmark them (also set labels (null)) and restore the background. Then click setTag(theTag) for the item and change the background to selected. Of course you can have some additional logic and mark multiple items. Note that once the View is destroyed, you lose your selection (for example, during deployment).
  2. Have some custom map or something that will contain the View’s unique ID and (un)tagged state. This is the best solution to allow persistent choices to be maintained across scrolling and expanding.
  3. Introduce a “tag” state in the backing adapter. As a result, tags persist even between application starts/stops. However, this is not a good approach because selection is more of a UI behavior.

I’m currently using a selection pattern multiple of the list for ExpandableListView selection. But, as I said, because the selection is by location, I have to make sacrifices in terms of functionality – that is, I clear the selection whenever I do it. The previous implementation was to use a custom Map to save the selected ID, which is honestly the better approach.

This is how I get the selected ID (remember I’m using multiple selection mode):

final SparseBooleanArray checkedPositions = expList.getCheckedItemPositions();
final ExpandableListAdapter adapter = expList.getExpandableListAdapter();
List<Long> checkedIds = new ArrayList<Long>();
if (packedPositionType == ExpandableListView.PACKED_POSITION_TYPE_GROUP) {
    for (int i = checkedPositions.size() - 1; i >= 0; i--) {
        if (checkedPositions.valueAt(i)) {
            checkedIds.add(adapter.getGroupId(checkedPositions.keyAt(i)));
        }
    }
}

However, in your case, you need to check the CHILD fill position. Also note that my adapter has a stable (unique) ID. If you don’t have a stable ID, then you can rely on ExpandableListView’s getPackedPositionForChild() method and store the markup packaging location.

Related Problems and Solutions