Change expandable indicator in ExpandableListView
Asked Answered
W

7

48

Trying to create an ExpandableListView. The initial view with the groups shows up fine. However, when I click the list item, my arrow does not change. See the images below.

enter image description here

How can I change the arrow's direction?

The layout XML:

  <ExpandableListView
        android:id="@+id/expandable_list"
        android:layout_width="fill_parent"
        android:layout_height="match_parent"            
        android:divider="@null"
        android:background="#ffffff"
        android:groupIndicator="@drawable/settings_selector"
        android:transcriptMode="alwaysScroll" />

settings_selector.xml:

 <?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android" >

<selector xmlns:android="http://schemas.android.com/apk/res/android" >
    <item
        android:drawable="@drawable/arrow_down"
        android:state_empty="true"/>
    <item
        android:drawable="@drawable/arrow_right"
        android:state_expanded="true"/>
</selector>

</animation-list>
Wolbrom answered 19/3, 2013 at 13:53 Comment(7)
Post the listView row xmlTremulous
@RajeshCP see update oneWolbrom
Onclick of the onItemClick function you can change the source of the group_indicator for that you need a uparrow button or else you can rotate the bitmap by some dregree and set it as a source for that ImageViewTremulous
@RajeshCP in left side arrow working nice use this hrupin.com/2012/08/… one but how to solve right side arrowWolbrom
Edit your lay out accordingly for thatTremulous
for which one i want how to change that left side button to right side @RajeshCPWolbrom
let us continue this discussion in chatWolbrom
W
67

expandable listview

 <ExpandableListView
    android:id="@+id/expandable_list"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:groupIndicator="@drawable/group_indicator"
    android:transcriptMode="alwaysScroll" />

setindicator here iam useing setindicator code like this this working nice

 DisplayMetrics metrics = new DisplayMetrics();
    getWindowManager().getDefaultDisplay().getMetrics(metrics);
    int width = metrics.widthPixels; 

 mExpandableList = (ExpandableListView)findViewById(R.id.expandable_list);
 mExpandableList.setIndicatorBounds(width - GetPixelFromDips(50), width - GetPixelFromDips(10));  

   public int GetPixelFromDips(float pixels) {
    // Get the screen's density scale 
    final float scale = getResources().getDisplayMetrics().density;
    // Convert the dps to pixels, based on density scale
    return (int) (pixels * scale + 0.5f);
}

res/drawable/group_indicator

  <?xml version="1.0" encoding="utf-8"?>

     <selector xmlns:android="http://schemas.android.com/apk/res/android">            
           <item android:drawable="@drawable/arrow_right" android:state_empty="true">  </item>            
           <item android:drawable="@drawable/arrow_down" android:state_expanded="true"></item>                
           <item android:drawable="@drawable/arrow_right"></item>
     </selector>
Wolbrom answered 20/3, 2013 at 8:37 Comment(4)
mExpandableList.setIndicatorBounds(width - 50, width - 10); gives Same output.. Why?????Cowart
use expListView.setIndicatorBoundsRelative in android 4.3Alejandroalejo
You can save indicator size in dimens.xml: <dimen name="indicator_bounds">-50dp</dimen> And then use built in method to calculate dp to pixels: getResources().getDimensionPixelSize(R.dimen.indicator_bounds)Fungus
icon is streched to the height of the layoutConnecticut
S
26

Try that for your settings_selector.xml:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >

    <item
        android:drawable="@drawable/arrow_right"
        android:state_expanded="true" />

    <item
        android:drawable="@drawable/arrow_down" />

</selector>
Surratt answered 20/3, 2013 at 8:2 Comment(2)
You didn't post your answer when I posted mine :)Surratt
becouse it is is usefull to any new developers.Wolbrom
L
17

I had gone the way below: decide the left/right drawable for your groupView based on isExpanded flag.
By that way, it is easier for us to customize the padding/background and other things of the indicator drawable.

Hope it helps.

    public View getGroupView(int groupPosition, boolean isExpanded, View convertView,
            ViewGroup parent) {
        TextView textView = (TextView) mLayoutInflater.inflate(R.layout.menu_group, null);
        textView.setCompoundDrawablesWithIntrinsicBounds(0, 0, isExpanded ? 0 : android.R.drawable.ic_menu_more, 0);
        textView.setText(getGroup(groupPosition).toString());
        return textView;
    }
Lunseth answered 12/5, 2014 at 8:13 Comment(0)
T
4
import java.util.ArrayList;

import android.app.Activity;
import android.content.Context;
import android.database.DataSetObserver;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.BaseExpandableListAdapter;
import android.widget.ExpandableListView;
import android.widget.TextView;

public class MyActivity extends Activity {

    private ExpandableListView mExpandableList;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_my);


        mExpandableList = (ExpandableListView)findViewById(R.id.expandable_list);
        mExpandableList.setGroupIndicator(null);
        ArrayList<Parent> arrayParents = new ArrayList<Parent>();
        ArrayList<String> arrayChildren = new ArrayList<String>();

        //here we set the parents and the children
        for (int i = 0; i < 10; i++){
            //for each "i" create a new Parent object to set the title and the children
            Parent parent = new Parent();
            parent.setTitle("Parent " + i);

            arrayChildren = new ArrayList<String>();
            for (int j = 0; j < 10; j++) {
                arrayChildren.add("Child " + j);
            }
            parent.setArrayChildren(arrayChildren);

            //in this array we add the Parent object. We will use the arrayParents at the setAdapter
            arrayParents.add(parent);
        }

        //sets the adapter that provides data to the list.
        mExpandableList.setAdapter(new MyCustomAdapter(MyActivity.this,arrayParents));

    }

    public class Parent {
        private String mTitle;
        private ArrayList<String> mArrayChildren;

        public String getTitle() {
            return mTitle;
        }

        public void setTitle(String mTitle) {
            this.mTitle = mTitle;
        }

        public ArrayList<String> getArrayChildren() {
            return mArrayChildren;
        }

        public void setArrayChildren(ArrayList<String> mArrayChildren) {
            this.mArrayChildren = mArrayChildren;
        }
    }




    public class MyCustomAdapter extends BaseExpandableListAdapter implements OnClickListener{


        private LayoutInflater inflater;
        private ArrayList<Parent> mParent;

        public MyCustomAdapter(Context context, ArrayList<Parent> parent){
            mParent = parent;
            inflater = LayoutInflater.from(context);
        }


        @Override
        //counts the number of group/parent items so the list knows how many times calls getGroupView() method
        public int getGroupCount() {
            return mParent.size();
        }

        @Override
        //counts the number of children items so the list knows how many times calls getChildView() method
        public int getChildrenCount(int i) {
            return mParent.get(i).getArrayChildren().size();
        }

        @Override
        //gets the title of each parent/group
        public Object getGroup(int i) {
            return mParent.get(i).getTitle();
        }

        @Override
        //gets the name of each item
        public Object getChild(int i, int i1) {
            return mParent.get(i).getArrayChildren().get(i1);
        }

        @Override
        public long getGroupId(int i) {
            return i;
        }

        @Override
        public long getChildId(int i, int i1) {
            return i1;
        }

        @Override
        public boolean hasStableIds() {
            return true;
        }

        @Override
        //in this method you must set the text to see the parent/group on the list
        public View getGroupView(int i, boolean b, View view, ViewGroup viewGroup) {

            if (view == null) {
                view = inflater.inflate(R.layout.list_item_parent, viewGroup,false);
            }
            view.findViewById(R.id.button).setTag(i);
            view.findViewById(R.id.button).setOnClickListener(this);
            TextView textView = (TextView) view.findViewById(R.id.list_item_text_view);
            //"i" is the position of the parent/group in the list
            textView.setText(getGroup(i).toString());

            //return the entire view
            return view;
        }

        @Override
        //in this method you must set the text to see the children on the list
        public View getChildView(int i, int i1, boolean b, View view, ViewGroup viewGroup) {
            if (view == null) {
                view = inflater.inflate(R.layout.list_item_child, viewGroup,false);
            }

            TextView textView = (TextView) view.findViewById(R.id.list_item_text_child);
            //"i" is the position of the parent/group in the list and
            //"i1" is the position of the child
            textView.setText(mParent.get(i).getArrayChildren().get(i1));

            //return the entire view
            return view;
        }

        @Override
        public boolean isChildSelectable(int i, int i1) {
            return true;
        }

        @Override
        public void registerDataSetObserver(DataSetObserver observer) {
            /* used to make the notifyDataSetChanged() method work */
            super.registerDataSetObserver(observer);
        }


        /* (non-Javadoc)
         * @see android.view.View.OnClickListener#onClick(android.view.View)
         * @since Mar 20, 2013
         * @author rajeshcp 
         */
        @Override
        public void onClick(View v) {
            if(mExpandableList.isGroupExpanded((Integer)v.getTag()))
        {
            mExpandableList.collapseGroup((Integer)v.getTag());
        }else
        {
            mExpandableList.expandGroup((Integer)v.getTag());
        }
        }
    }


}

Change your MyActivity like this and let me know what else you want ?

Tremulous answered 20/3, 2013 at 6:17 Comment(6)
in this no onitemclick in expandablelistview necessary to use an onitemclick.Wolbrom
I really don understand what you want ?Tremulous
see hrupin.com/2012/08/… this example in place of left side image how change that image to right side.Wolbrom
I'am useing that example only that image how to change like left to right side same as my image like in question have one image like that..Wolbrom
hey see the edited answer after running the application just click on each buttons in the rowTremulous
Any way thanks my issue solved we see my answer working nice.Wolbrom
C
4

subject:

    int width = getResources().getDisplayMetrics().widthPixels;
    if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.JELLY_BEAN_MR2) {
        listView.setIndicatorBounds(width - getPixelValue(40), width - getPixelValue(10));
    } else {
        listView.setIndicatorBoundsRelative(width - getPixelValue(40), width - getPixelValue(10));
    }

and helper method:

public static int getPixelValue(int dp) {

    final float scale = getResources().getDisplayMetrics().density;
    return (int) (dp * scale + 0.5f);
}
Crossway answered 31/10, 2014 at 16:5 Comment(0)
B
2

I am a bit late to the party but my requirement was something similar to this but something was different.

enter image description here

I had 3 requirements:

  1. if a group have child then show down_arrow (V)
  2. if a group doesn't have a child then no arrow/image
  3. if a group with child expanded then show up_arrow (^)

To achieve something similar to this:

  1. Your ExpandableListView will look something similar to this with android:groupIndicator null

     <ExpandableListView
     android:id="@+id/expandableListView"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:divider="@android:color/darker_gray"
     android:dividerHeight="0.5dp"
     android:groupIndicator="@null" />
    
  2. Your group/header layout will look something like this with text and image at the end:

<androidx.appcompat.widget.AppCompatImageView
    android:id="@+id/ivDrawerHeaderItemIcon"
    android:layout_width="@dimen/dp_30"
    android:layout_height="@dimen/dp_30"
    android:layout_gravity="center_vertical"
    android:layout_marginStart="@dimen/dp_10"
    android:layout_marginEnd="@dimen/dp_10"
    android:src="@drawable/switch" />

<androidx.appcompat.widget.AppCompatTextView
    android:id="@+id/lblListHeader"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    android:layout_margin="@dimen/dp_5"
    android:layout_weight="1"
    android:fontFamily="@font/roboto_condensed_regular"
    android:gravity="center_vertical"
    android:padding="@dimen/dp_10"
    android:textAllCaps="true"
    android:textColor="@android:color/white"
    android:textSize="@dimen/sp_16" />

<androidx.appcompat.widget.AppCompatImageView
    android:id="@+id/ivIcon"
    android:layout_width="@dimen/dp_15"
    android:layout_height="@dimen/dp_15"
    android:layout_gravity="center_vertical"
    android:layout_marginStart="@dimen/dp_10"
    android:layout_marginEnd="@dimen/dp_10" />
  1. In your BaseExpandableListAdapter's getGroupView() method, use

         if (Objects.requireNonNull(expandableListDetail.get(expandableListTitle.get(listPosition))).size() > 0) {
         if (isExpanded) {
             ivIcon.setImageResource(R.drawable.arrow_up);
         } else {
             ivIcon.setImageResource(R.drawable.arrow_down);
         }
     }
    

Where, expandableListTitle is group and expandableListDetail is its children

Babby answered 19/8, 2020 at 8:24 Comment(0)
G
1

Just Create a view/Imageview where ever u want in the xml of group item example:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/parent_group"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="10dp">

<ImageView
    android:id="@+id/expandable_icon"
    android:layout_width="25dp"
    android:layout_height="25dp"
    android:layout_marginTop="6dp"
    android:src="@drawable/group_icon_not_expanded" />

<TextView
    android:id="@+id/group_name"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    android:layout_marginLeft="10dp"
    android:fontFamily="@font/roboto_thin"
    android:textColor="@android:color/black"
    android:textSize="17sp" />

And then for your ExpandableListView use a GroupClickListener to change the image for ImageView programmatically, example :

listView.setOnGroupClickListener(new ExpandableListView.OnGroupClickListener() {
        @Override
        public boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long id) {
            parent.smoothScrollToPosition(groupPosition);

            if (parent.isGroupExpanded(groupPosition)) {
                ImageView imageView = v.findViewById(R.id.expandable_icon);
                imageView.setImageDrawable(getResources().getDrawable(R.drawable.group_icon_not_expanded));
            } else {
                ImageView imageView = v.findViewById(R.id.expandable_icon);
                imageView.setImageDrawable(getResources().getDrawable(R.drawable.group_icon_expanded));
            }
            return false    ;
        }
    });
Girvin answered 3/7, 2018 at 6:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.