Changing the location of indicator in ExpandableListView causing problems

11,673

Here's an example of custom expandable list view:

What you want to see if you apply this code in your new project:

enter image description here

create this code into activity

public class ExpActivity extends Activity
{

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

        // Находим наш list 
        ExpandableListView listView = (ExpandableListView)findViewById(R.id.exListView);

        //Создаем набор данных для адаптера        
        ArrayList<ArrayList<String>> groups = new ArrayList<ArrayList<String>>();
        ArrayList<String> children1 = new ArrayList<String>();
        ArrayList<String> children2 = new ArrayList<String>();
        children1.add("Child_1");
        children1.add("Child_2");
        groups.add(children1);
        children2.add("Child_1");
        children2.add("Child_2");
        children2.add("Child_3");
        groups.add(children2);       
       //Создаем адаптер и передаем context и список с данными
        ExpListAdapter adapter = new ExpListAdapter(getApplicationContext(), groups);
        listView.setAdapter(adapter);
    }
} 

add expandableListView into main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
<ExpandableListView
        android:id="@+id/exListView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:indicatorLeft="250dp"
        android:indicatorRight="300dp"
    />
</LinearLayout>

create an adapter class

public class ExpListAdapter extends BaseExpandableListAdapter {

    private ArrayList<ArrayList<String>> mGroups;
    private Context mContext;

    public ExpListAdapter (Context context,ArrayList<ArrayList<String>> groups){
        mContext = context;
        mGroups = groups;
    }

    @Override
    public int getGroupCount() {
        return mGroups.size();
    }

    @Override
    public int getChildrenCount(int groupPosition) {
        return mGroups.get(groupPosition).size();
    }

    @Override
    public Object getGroup(int groupPosition) {
        return mGroups.get(groupPosition);
    }

    @Override
    public Object getChild(int groupPosition, int childPosition) {
        return mGroups.get(groupPosition).get(childPosition);
    }

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

    @Override
    public long getChildId(int groupPosition, int childPosition) {
        return childPosition;
    }

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

    @Override
    public View getGroupView(int groupPosition, boolean isExpanded, View convertView,
                             ViewGroup parent) {

        if (convertView == null) {
            LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = inflater.inflate(R.layout.group_view, null);
        }

        if (isExpanded){
           //Изменяем что-нибудь, если текущая Group раскрыта
        }
        else{
            //Изменяем что-нибудь, если текущая Group скрыта
        }

        TextView textGroup = (TextView) convertView.findViewById(R.id.textGroup);
        textGroup.setText("Group " + Integer.toString(groupPosition));

        return convertView;

    }

    @Override
    public View getChildView(int groupPosition, int childPosition, boolean isLastChild,
                             View convertView, ViewGroup parent) {
        if (convertView == null) {
            LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = inflater.inflate(R.layout.child_view, null);
        }

        TextView textChild = (TextView) convertView.findViewById(R.id.textChild);
        textChild.setText(mGroups.get(groupPosition).get(childPosition));

        Button button = (Button)convertView.findViewById(R.id.buttonChild);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Toast.makeText(mContext,"button is pressed",5000).show();
            }
        });

        return convertView;
    }

    @Override
    public boolean isChildSelectable(int groupPosition, int childPosition) {
        return true;
    }
}

the names of methods and parameters is quite informative. methods getGroupView and getChildView returns View for pparents and children accordingly. using the parameter isExpanded in the method getGroupView, we ca, for instance, change the back of group in different states. using LayoutInflater we use custom layout for our list.

group_view.xml

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

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="match_parent">
    <TextView
            android:id="@+id/textGroup"
            android:layout_width="wrap_content"
            android:layout_height="50dp"
            android:layout_marginLeft="5dp"
            android:layout_marginTop="20dp"
            android:textColor="@android:color/white"
            android:textStyle="bold"
            />
</LinearLayout>

child_view.xml

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

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="match_parent">
  <TextView
     android:id="@+id/textChild"
     android:layout_width="wrap_content"
     android:layout_height="40dp"
     android:layout_marginLeft="20dp"
     android:layout_marginTop="20dp"
     android:textColor="@android:color/white"
     />
  <Button
     android:id="@+id/buttonChild"
     android:layout_width="100dp"
     android:layout_height="40dp"
     android:layout_marginLeft="150dp"
     android:layout_marginTop="10dp"
     android:text="Button"
     android:focusable="false"
     />
</LinearLayout>

in the child view we added a button, in the adapter method getChildView controlling its pressed. in the similar way we can add buttons and other elements in group_view.xml .

also, we can pin listeners to our list.

•OnChildClickListener — pressing on an element •OnGroupCollapseListener – collapsing group •OnGroupExpandListener – expanding group •OnGroupClickListener – press on group

now lets look at groupIndicater - indicator of the group state. it's placement pointed in main.xml with parameters indicatorLeft, indicatorRigh - corresponding to left and right border. by default the indicator placed on the left side, what is not so cool.

also we can add custom images, for that, we need to add indicator.xml in the folder drawable with this code.

<?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/imageOpen">
    </item>
    <item android:state_empty="true"
          android:drawable="@drawable/imageClose">
    </item>
</selector>

where imageOpen is for expanded group imageClose is for collapsed group

next time we need to add a row for parameters of our list in main.xml

android:groupIndicator="@drawable/indicator"
Share:
11,673

Related videos on Youtube

Guy
Author by

Guy

Updated on September 16, 2022

Comments

  • Guy
    Guy over 1 year

    I'm trying to set my indicator to be next to the textview, but I just can't get the right code to do it.

    XML:

    <TextView
        android:id="@+id/lblListHeader"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:paddingLeft="?android:attr/expandableListPreferredItemPaddingLeft"
        android:textColor="#000000"
        android:textSize="17dp" />
    
    <ImageView
        android:id="@+id/imageView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_toLeftOf="@+id/lblListHeader"
        android:src="@drawable/custom_arrow" />
    

    This is the only stack of code that I have found researching but I can't get it to work:

    //inside getGropView method
    View v;
        if (convertView == null) {
            v = newGroupView(isExpanded, parent);
        } else {
            v = convertView;
        }
        bindView(v, mGroupData.get(groupPosition), mGroupFrom, mGroupTo);
        ((ImageView) v.findViewById(R.id.videos_group_indicator))
        .setImageResource(isExpanded?R.drawable.videos_chevron_expanded:R.drawable.videos_chevron_collapsed);
        return v;
    

    The main problem is that it "underlines" the newGroupView method etc. because I don't have such method and it is not mentioned how to create it in the example I was looking at.

    Also, once I get the solution, could someone please try and explain this code to me? I have read it through a lot of time and I just can't get myself to understand it, I'm a beginner.

  • Guy
    Guy over 10 years
    Thanks for the reply, I changed the XML, but the problem is still in the java code. It still underlines "newGroupView" because there's no such method in my code.