androidexpandablelistviewandroid-drawableexpandablelistadapter

ExpandableListView change drawable state_expanded


I got a problem on my ExpandableListAdapter. I used a custom image as the indicator, because I wanted to position it to the right and not to the left of the menu item. I also need to hide the indicator on some items.

My drawable looks like this:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item
    android:state_expanded="true"
    android:drawable="@drawable/arrow_up" />
<item
    android:drawable="@drawable/arrow_down" />
</selector>

So I make use of the state_expanded of Android.

My DrawerLayout has this LinearLayout in it:

<LinearLayout
    android:id="@+id/drawer_linear_layout"
    android:layout_width="@dimen/menu_width"
    android:layout_height="match_parent"
    android:layout_gravity="start"
    android:orientation="vertical">

    <ExpandableListView
        android:id="@+id/navigationmenu"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:choiceMode="singleChoice"
        android:layout_marginTop="@dimen/nav_header_height"
        android:childDivider="@android:color/transparent"
        android:headerDividersEnabled="true"
        android:groupIndicator="@android:color/transparent"
        android:background="@drawable/border_shadow">
    </ExpandableListView>

</LinearLayout>

I hide the normal groupIndicator manually to add the custom Drawable later in code.

My ExpandableListAdapter seems to be correct:

public class ExpandableListAdapter extends BaseExpandableListAdapter {
    ...

    private static final int[] EMPTY_STATE_SET = {};
    private static final int[] GROUP_EXPANDED_STATE_SET = { android.R.attr.state_expanded };
    private static final int[][] GROUP_STATE_SETS = {
        EMPTY_STATE_SET, // 0
        GROUP_EXPANDED_STATE_SET //1
    };

    ...

    @Override
    public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
        MOMenuItem headerTitle = (MOMenuItem) getGroup(groupPosition);

        LayoutInflater infalInflater = (LayoutInflater) this.mContext
            .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        LinearLayout linLayout = (LinearLayout) infalInflater.inflate(R.layout.list_header, parent, false);
        convertView = linLayout;

        View indicator = convertView.findViewById(R.id.indicator_image);

        if (groupPosition == 1) {
            Log.d("GetGroupView", "Called!");
        }

        if (indicator != null) {
            ImageView indicatorImage = (ImageView) indicator;
            if (getChildrenCount(groupPosition) == 0) {
                indicatorImage.setVisibility(View.INVISIBLE);
            } else {
                if (groupPosition == 1) {
                    Log.d("IsExpanded is", "" + isExpanded);
                }
                indicatorImage.setVisibility(View.VISIBLE);
                int stateSetIndex = (isExpanded ? 1 : 0);
                if (groupPosition == 1) {
                    Log.d("State Index", "" + stateSetIndex);
                }
                Drawable drawable = indicatorImage.getDrawable();
                drawable.setState(GROUP_STATE_SETS[stateSetIndex]);
            }
        }

        ...

        return convertView;
    }
}

The problem is that the indicator doesn't get updated. However, the output of the Log-Statements for the item at index 1, when opened is:

  1. GetGroupView: Called!
  2. IsExpanded is: true
  3. State Index: 1

The indicator stays the same.


Solution

  • After long research and trial and error I did not find a way to make it work with states. However, I used the images itself like the following:

    public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
        MOMenuItem headerTitle = (MOMenuItem) getGroup(groupPosition);
    
        LayoutInflater infalInflater = (LayoutInflater) this.mContext
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        LinearLayout linLayout = (LinearLayout) infalInflater.inflate(R.layout.list_header, parent, false);
        convertView = linLayout;
    
        View indicator = convertView.findViewById(R.id.indicator_image);
    
        if (indicator != null) {
            ImageView indicatorImage = (ImageView) indicator;
            if (getChildrenCount(groupPosition) == 0) {
                indicatorImage.setVisibility(View.INVISIBLE);
            } else {
                indicatorImage.setVisibility(View.VISIBLE);
    
                if (isExpanded) {
                    indicatorImage.setImageResource(R.drawable.arrow_up);
                } else {
                    indicatorImage.setImageResource(R.drawable.arrow_down);
                }
            }
        }
    
        ...
    }
    

    Sadly, the cleaner solution with a drawable and a state wasn't working. I hope this will help others stumbling upon this question.