Android ExpandableList Move Item From Group to Another on Click

I needed an expandable list that would let us move item from a group to another. So I wrote this simple tutorial. It’s nothing difficult to achieve on your own, but I wanted to add this code here in case someone will need it. So, we will create an ExpandableList with items that can be moved to a new desired group when they are clicked (it’s not a drag’n drop example :P).

1. Create a new simple project in Android

2. Go to res – layout – activity_main.xml and add an ExpandableListView like this:

<?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"
    android:orientation="vertical">

    <ExpandableListView
        android:id="@+id/expandable_list"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:cacheColorHint="#00000000"
        android:transcriptMode="disabled" />

</LinearLayout>

3. Now, create 2 new xml files in res – layout. Name the first one as list_item_parent.xml and the other one as list_item_child.xml. Below is the code for both.

list_item_parent.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/list_item"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal">

    <TextView
        android:id="@+id/list_item_text_view"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginLeft="35dp"
        android:layout_weight="1"
        android:padding="10dp"
        android:textSize="20sp" />

</LinearLayout>

list_item_child.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/list_item_child"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center_vertical"
    android:orientation="vertical">

    <TextView
        android:id="@+id/list_item_text_child"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="5dp"
        android:padding="10dp"
        android:textSize="20sp" />

</LinearLayout>

4. Now, we have to create a ”model” class for displaying the groups. So, go to the java package, right click on your project package and create a new Java class. Name it Parent. Below is the code for this class:

Parent.java

package com.example.expandablelistremove;

import java.util.List;

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

    public String getTitle() {
        return mTitle;
    }

    public void setTitle(String title) {
        mTitle = title;
    }

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

    public void setArrayChildren(List<String> arrayChildren) {
        mArrayChildren = arrayChildren;
    }
}

5. Now, we have to create another java class for the ExpandableListView’s adapter. We will name this class MyCustomAdapter.

MyCustomAdapter.java

package com.example.expandablelistremove;

import android.content.Context;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseExpandableListAdapter;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.List;

public class MyCustomAdapter extends BaseExpandableListAdapter {

    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 groupPosition) {
        Log.e("EXPANDABLE LIST", "GROUP " + groupPosition + " " + mParent.get(groupPosition).getArrayChildren()
                .size() + "");
        return mParent.get(groupPosition).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
    public int getChildTypeCount() {
        return 6;
    }

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

        ViewHolder holder = new ViewHolder();
        holder.groupPosition = groupPosition;

        if (convertView == null) {
            convertView = inflater.inflate(R.layout.list_item_parent, viewGroup, false);
            holder.groupTitle = (TextView) convertView.findViewById(R.id.list_item_text_view);
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }

        holder.groupTitle.setText(getGroup(groupPosition).toString());


        //return the entire view
        return convertView;
    }

    @Override
    //in this method you must set the text to see the children on the list
    public View getChildView(final int groupPosition, final int childPosition,
                             boolean isLastChild, View convertView, ViewGroup viewGroup) {

        final ViewHolder holder;
        if (convertView == null) {
            holder = new ViewHolder();
            convertView = inflater.inflate(R.layout.list_item_child, viewGroup, false);
            holder.childTitle = (TextView) convertView.findViewById(R.id.list_item_text_child);

            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }

        holder.childTitle.setText(mParent.get(groupPosition).getArrayChildren().get(childPosition));

        convertView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                addChildToGroup(mParent.get(groupPosition).getArrayChildren().get
                        (childPosition), mParent.size() - 1, "Parent 25 (Hardcoded)");
                removeChildFromGroup(groupPosition, childPosition);

            }
        });

        //return the entire view
        return convertView;
    }

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

    public void removeGroup(int groupPosition) {
        mParent.remove(groupPosition);
        Log.e("removeGroup", "group size " + mParent.size());
        notifyDataSetChanged();
    }

    /**
     * Removes child at childPosition from group at groupPosition. If it is the last child in group
     * the group will also be deleted.
     *
     * @param groupPosition Position of the group in which the child exists
     * @param childPosition Position of the child in the group
     */
    public void removeChildFromGroup(int groupPosition, int childPosition) {
        Parent parent = mParent.get(groupPosition);

        parent.getArrayChildren().remove(childPosition);

        if (parent.getArrayChildren().isEmpty()) {
            removeGroup(groupPosition);
        } else {
            notifyDataSetChanged();
        }
    }

    public void addChildToGroup(String childName, int groupPosition, String sectionTitle) {
        Parent parent = mParent.get(groupPosition);
        List<String> arrayChildren = parent.getArrayChildren();

        if (!parent.getTitle().equals(sectionTitle)) {
            parent = new Parent();
            arrayChildren = new ArrayList<>();

            parent.setTitle(sectionTitle);

            mParent.add(parent);
        }

        arrayChildren.add(childName);
        parent.setArrayChildren(arrayChildren);

        notifyDataSetChanged();
    }

    protected class ViewHolder {
        protected int groupPosition;
        protected TextView groupTitle;
        protected TextView childTitle;
    }
}

6. Now go to the MainActivity class (the activity that was created automatically when you created the project) and add the following code:

MainActivity.java

package com.example.expandablelistremove;
import android.app.Activity;
import android.os.Bundle;
import android.widget.ExpandableListView;

import java.util.ArrayList;

public class MainActivity extends Activity {
    private ExpandableListView mExpandableList;

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

        mExpandableList = (ExpandableListView)findViewById(R.id.expandable_list);

        ArrayList<Parent> arrayParents = new ArrayList<>();
        ArrayList<String> arrayChildren;

        //here we set the parents and the children
        for (int i = 0; i < 14; 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<>();

            for (int j = 0; j < 3; j++) {
                arrayChildren.add(" Group " + i + " Child " + j);
                if (i == 0 || i == 5) {
                    break;
                }
            }
            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(MainActivity.this,arrayParents));

        // Always expand the views
        for (int i = 0; i < arrayParents.size(); i++) {
            mExpandableList.expandGroup(i);
        }
    }
}

And that’s it. Now, whenever you click on an item, it will automatically be moved to a new group that was hardcoded as “Group 25 (Hardcoded)” and which is at the bottom of the list. The group is created only once, when no items were added to it. After that, the items will be just moved to this group.

I hope I will enjoy it and feel free to post comments or suggestions 😀

keyboard_arrow_up