Deepshikha Puri, the young Indian Entrepreneur heading the mobile development trade from years to successive extent, has worked with numerous clients and many tremendous brands in this industry of mobile encompassing in India and overseas maintaining promising work relationships with each of them with an impression to manage it's whole thing.

Saturday, July 22, 2017

Navigation drawer with expandablelistview in android

Video Demo:

In this tutorial I am using expandable listview with default navigation drawer. Download source code from here

android custom navigation drawer with expandablelistview

activity_main.xml:
<android.support.v4.widget.DrawerLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >


    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <LinearLayout
            android:id="@+id/container_toolbar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">

        </LinearLayout>
<LinearLayout
    android:layout_width="match_parent"
    android:orientation="vertical"
    android:layout_height="match_parent">

    <RelativeLayout
        android:layout_width="match_parent"
        android:background="#234E6F"
        android:layout_height="60dp">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="20dp"
            android:textColor="#ffffff"
            android:layout_centerInParent="true"
            android:textStyle="bold"
            android:id="@+id/tv_name"/>


        <ImageView
            android:layout_width="25dp"
            android:layout_centerVertical="true"
            android:layout_height="30dp"
            android:layout_marginLeft="10dp"
            android:src="@drawable/menu_icon"/>
        <RelativeLayout
            android:layout_width="40dp"
            android:id="@+id/rl_menu"
            android:layout_height="match_parent"></RelativeLayout>

    </RelativeLayout>

        <FrameLayout
            android:id="@+id/content_frame"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
</LinearLayout>

    </LinearLayout>
    <LinearLayout
        android:id="@+id/left_drawer"
        android:layout_width="240dp"
        android:orientation="vertical"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:background="#FFFFFF">

        <include layout="@layout/menu_layout"></include>

    </LinearLayout>

</android.support.v4.widget.DrawerLayout>
menu_layout.xml:

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

<ScrollView android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:android="http://schemas.android.com/apk/res/android" >
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#FFFFFF"
    android:orientation="vertical">


    <RelativeLayout
        android:id="@+id/rl_profile"
        android:layout_width="match_parent"
        android:layout_height="150dp">

        <ImageView

            android:id="@+id/iv_image"
            android:layout_width="100dp"
            android:layout_height="100dp"
            android:layout_centerVertical="true"
            android:src="@drawable/profile_image" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:layout_marginLeft="20dp"
            android:layout_toRightOf="@+id/iv_image"
            android:text="David"
            android:textColor="#000000"
            android:textSize="15dp" />


    </RelativeLayout>

    <View
        android:layout_width="match_parent"
        android:layout_height="2dp"
        android:background="#EAEAEA"></View>


    <ExpandableListView
        android:id="@+id/ev_menu"
        android:nestedScrollingEnabled="false"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

    </ExpandableListView>
</LinearLayout>
</ScrollView>
MainActivity.java:
package com.deepshikha.navigationdrawer;

import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ExpandableListAdapter;
import android.widget.ExpandableListView;
import android.widget.RelativeLayout;
import android.widget.TextView;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {

    ArrayList al_main = new ArrayList<>();
    ExpandableListView ev_list;
    CountryAdapter obj_adapter;
    String TAG = "MainActivity";
    private DrawerLayout mDrawerLayout;
    HomeFragment fragment;
    TextView tv_name;
    RelativeLayout rl_menu;

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

    }

    private void init() {

        getSupportActionBar().hide();
        ev_list = (ExpandableListView) findViewById(R.id.ev_menu);
        tv_name = (TextView) findViewById(R.id.tv_name);
        rl_menu = (RelativeLayout) findViewById(R.id.rl_menu);
        mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
        obj_adapter = new CountryAdapter(MainActivity.this, al_main);
        ev_list.setAdapter(obj_adapter);
        ev_list.setOnGroupClickListener(new ExpandableListView.OnGroupClickListener() {

            @Override
            public boolean onGroupClick(ExpandableListView parent, View v,
                                        int groupPosition, long id) {
                setListViewHeight(parent, groupPosition);
                return false;
            }
        });

        setExpandableListViewHeightBasedOnChildren(ev_list);

        fragment = new HomeFragment();
        Bundle bundle = new Bundle();
        bundle.putString("name", al_main.get(0).getStr_country());
        bundle.putString("des", al_main.get(0).getAl_state().get(0).getStr_description());
        bundle.putString("dish", al_main.get(0).getAl_state().get(0).getStr_name());
        bundle.putString("image", al_main.get(0).getAl_state().get(0).getStr_image());
        tv_name.setText(al_main.get(0).getStr_country());

        fragment.setArguments(bundle);
        getSupportFragmentManager().beginTransaction().replace(R.id.content_frame, fragment, "HomeFragment").addToBackStack("null").commit();


        rl_menu.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                mDrawerLayout.openDrawer(Gravity.LEFT);
            }
        });
    }

    private void setListViewHeight(ExpandableListView listView, int group) {
        ExpandableListAdapter listAdapter = (ExpandableListAdapter) listView.getExpandableListAdapter();
        int totalHeight = 0;
        int desiredWidth = View.MeasureSpec.makeMeasureSpec(listView.getWidth(),
                View.MeasureSpec.EXACTLY);
        for (int i = 0; i < listAdapter.getGroupCount(); i++) {
            View groupItem = listAdapter.getGroupView(i, false, null, listView);
            groupItem.measure(desiredWidth, View.MeasureSpec.UNSPECIFIED);

            totalHeight += groupItem.getMeasuredHeight();

            if (((listView.isGroupExpanded(i)) && (i != group))
                    || ((!listView.isGroupExpanded(i)) && (i == group))) {
                for (int j = 0; j < listAdapter.getChildrenCount(i); j++) {
                    View listItem = listAdapter.getChildView(i, j, false, null,
                            listView);
                    listItem.measure(desiredWidth, View.MeasureSpec.UNSPECIFIED);

                    totalHeight += listItem.getMeasuredHeight();

                }
            }
        }

        ViewGroup.LayoutParams params = listView.getLayoutParams();
        int height = totalHeight
                + (listView.getDividerHeight() * (listAdapter.getGroupCount() - 1));
       /* if (height < 10)
            height = 200;*/
        params.height = height;
        listView.setLayoutParams(params);
        listView.requestLayout();

    }

    private void fn_data() {

        String str_data = loadJSONFromAsset();

        try {
            JSONObject jsonObject_country = new JSONObject(str_data);
            JSONArray jsonArray_country = jsonObject_country.getJSONArray("country");
            al_main = new ArrayList<>();
            for (int i = 0; i < jsonArray_country.length(); i++) {
                Model_country obj_country = new Model_country();
                JSONObject jsonObject = jsonArray_country.getJSONObject(i);
                JSONArray jsonArray_dishes = jsonObject.getJSONArray("dishes");
                ArrayList al_dishes = new ArrayList<>();
                for (int j = 0; j < jsonArray_dishes.length(); j++) {

                    JSONObject jsonObject_dishes = jsonArray_dishes.getJSONObject(j);
                    Model_Dish obj_dish = new Model_Dish();
                    obj_dish.setStr_name(jsonObject_dishes.getString("dishname"));
                    obj_dish.setStr_description(jsonObject_dishes.getString("description"));
                    obj_dish.setStr_image(jsonObject_dishes.getString("image"));
                    al_dishes.add(obj_dish);
                }

                obj_country.setAl_state(al_dishes);
                obj_country.setStr_country(jsonObject.getString("name"));

                al_main.add(obj_country);
            }
        } catch (JSONException e) {
            e.printStackTrace();
        }

    }

    public static void setExpandableListViewHeightBasedOnChildren(ExpandableListView expandableListView) {
        CountryAdapter adapter = (CountryAdapter) expandableListView.getExpandableListAdapter();
        if (adapter == null) {
            return;
        }
        int totalHeight = expandableListView.getPaddingTop() + expandableListView.getPaddingBottom();
        for (int i = 0; i < adapter.getGroupCount(); i++) {
            View groupItem = adapter.getGroupView(i, false, null, expandableListView);
            groupItem.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
            totalHeight += groupItem.getMeasuredHeight();

            if (expandableListView.isGroupExpanded(i)) {
                for (int j = 0; j < adapter.getChildrenCount(i); j++) {
                    View listItem = adapter.getChildView(i, j, false, null, expandableListView);
                    listItem.setLayoutParams(new ViewGroup.LayoutParams(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED));
                    listItem.measure(View.MeasureSpec.makeMeasureSpec(0,
                            View.MeasureSpec.UNSPECIFIED), View.MeasureSpec
                            .makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
                    totalHeight += listItem.getMeasuredHeight();

                }
            }
        }

        ViewGroup.LayoutParams params = expandableListView.getLayoutParams();
        int height = totalHeight + expandableListView.getDividerHeight() * (adapter.getGroupCount() - 1);

        if (height < 10)
            height = 100;
        params.height = height;
        expandableListView.setLayoutParams(params);
        expandableListView.requestLayout();
    }

    public String loadJSONFromAsset() {
        String json = null;
        try {

            InputStream is = getAssets().open("dishes.json");

            int size = is.available();

            byte[] buffer = new byte[size];

            is.read(buffer);

            is.close();

            json = new String(buffer, "UTF-8");


        } catch (IOException ex) {
            ex.printStackTrace();
            return null;
        }

        Log.e(TAG, "Json response " + json);
        return json;

    }

    public void fn_selectedPosition(int group, int child) {

        fragment = new HomeFragment();
        Bundle bundle = new Bundle();
        bundle.putString("name", al_main.get(group).getStr_country());
        bundle.putString("des", al_main.get(group).getAl_state().get(child).getStr_description());
        bundle.putString("dish", al_main.get(group).getAl_state().get(child).getStr_name());
        bundle.putString("image", al_main.get(group).getAl_state().get(child).getStr_image());
        fragment.setArguments(bundle);

        getSupportFragmentManager().beginTransaction().replace(R.id.content_frame, fragment, "HomeFragment").addToBackStack("null").commit();
        mDrawerLayout.closeDrawer(Gravity.LEFT);

        tv_name.setText(al_main.get(group).getStr_country());
    }

    @Override
    public void onBackPressed() {
        super.onBackPressed();
        finish();
    }
}
Model_country.java:
package com.deepshikha.navigationdrawer;

import java.util.ArrayList;

/**
 * Created by deepshikha on 12/7/17.
 */

public class Model_country {
    String str_country;
    ArrayList al_state;
    public Model_country() {
    }

    public Model_country(String str_country, ArrayList al_state) {
        this.str_country = str_country;
        this.al_state = al_state;
    }


    public String getStr_country() {
        return str_country;
    }

    public void setStr_country(String str_country) {
        this.str_country = str_country;
    }

    public ArrayList getAl_state() {
        return al_state;
    }

    public void setAl_state(ArrayList al_state) {
        this.al_state = al_state;
    }
}
Model_Dish.java:
package com.deepshikha.navigationdrawer;

/**
 * Created by deepshikha on 12/7/17.
 */

public class Model_Dish {
    String str_name;
    String str_description;
    String str_image;

    public Model_Dish(String str_name, String str_description, String str_image) {
        this.str_name = str_name;
        this.str_description = str_description;
        this.str_image = str_image;
    }

    public String getStr_image() {
        return str_image;
    }

    public void setStr_image(String str_image) {
        this.str_image = str_image;
    }

    public Model_Dish() {

    }



    public String getStr_name() {
        return str_name;
    }

    public void setStr_name(String str_name) {
        this.str_name = str_name;
    }

    public String getStr_description() {
        return str_description;
    }

    public void setStr_description(String str_description) {
        this.str_description = str_description;
    }
}
fragment_home.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"
    android:background="#FFFFFF"
    android:orientation="vertical">

<RelativeLayout
    android:layout_width="match_parent"
    android:background="#FFFFFF"
    android:layout_height="240dp">

    <ImageView
        android:layout_width="match_parent"
        android:layout_height="200dp"
        android:layout_marginTop="20dp"
        android:scaleType="centerCrop"
        android:id="@+id/iv_image"/>
</RelativeLayout>

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Dish Name"
        android:textSize="25dp"
        android:id="@+id/tv_dishname"
        android:gravity="center"
        android:textStyle="bold"
        android:textColor="#000000"
        />

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Dish Name"
        android:textSize="18dp"
        android:padding="10dp"
        android:layout_marginTop="5dp"
        android:id="@+id/tv_description"
        android:gravity="left"
        android:textColor="#000000"
        />

</LinearLayout>

HomeFragment.java:
package com.deepshikha.navigationdrawer;

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;


public class HomeFragment extends Fragment {

    View view;
    TextView  tv_dishname, tv_description;
    ImageView iv_image;
    String str_name, str_disname, str_des, str_imagename;

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        view = inflater.inflate(R.layout.fragment_home, container, false);
        init();
        return view;
    }

    private void init() {

        str_name = getArguments().getString("name");
        str_disname = getArguments().getString("dish");
        str_des = getArguments().getString("des");
        str_imagename = getArguments().getString("image");
//        str_imagename = "chinese";
        tv_dishname = (TextView) view.findViewById(R.id.tv_dishname);
        tv_description = (TextView) view.findViewById(R.id.tv_description);
        iv_image = (ImageView) view.findViewById(R.id.iv_image);


        tv_dishname.setText(str_disname);
        tv_description.setText(str_des);

        int resourceImage = getActivity().getResources().getIdentifier(str_imagename, "drawable", getActivity().getPackageName());
        iv_image.setImageResource(resourceImage);


    }


}
adapter_childview.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"
    android:layout_marginLeft="20dp"
    android:paddingLeft="50dp"
    android:orientation="vertical">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:textSize="15dp"
        android:gravity="center_vertical"
        android:textColor="#000000"
        android:id="@+id/tv_name"/>



</LinearLayout>
adapter_header.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"
    android:orientation="vertical">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:textSize="15dp"
        android:paddingLeft="10dp"
        android:gravity="center_vertical"
        android:textColor="#ffffff"
        android:background="#234E6F"
        android:id="@+id/tv_name"/>

</LinearLayout>

CountryAdapter.java:
package com.deepshikha.navigationdrawer;

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

import java.util.ArrayList;

/**
 * Created by deepshikha on 12/7/17.
 */

public class CountryAdapter extends BaseExpandableListAdapter {
    Context context;
    ArrayList al_country;

    public CountryAdapter(Context context, ArrayList al_country) {
        this.context = context;
        this.al_country = al_country;
    }

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

    @Override
    public int getChildrenCount(int i) {
        return al_country.get(i).getAl_state().size();
    }

    @Override
    public Object getGroup(int i) {
        return al_country.get(i);
    }

    @Override
    public Object getChild(int i, int i1) {
        return al_country.get(i).getAl_state().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 false;
    }

    @Override
    public View getGroupView(int i, boolean b, View view, ViewGroup viewGroup) {
        if (view==null){

            LayoutInflater layoutInflater = (LayoutInflater) this.context
                    .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            view = layoutInflater.inflate(R.layout.adapter_header, null);
        }
        TextView tv_state = (TextView)view.findViewById(R.id.tv_name);
        tv_state.setText(al_country.get(i).getStr_country());
        return view;
    }

    @Override
    public View getChildView(final int i, final int i1, boolean b, View view, ViewGroup viewGroup) {
        if (view==null){

            LayoutInflater layoutInflater = (LayoutInflater) this.context
                    .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            view = layoutInflater.inflate(R.layout.adapter_childview, null);
        }

        TextView tv_state = (TextView)view.findViewById(R.id.tv_name);

        tv_state.setText(al_country.get(i).getAl_state().get(i1).getStr_name());
        tv_state.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                ((MainActivity)context).fn_selectedPosition(i,i1);
            }
        });
        return view;
    }

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


}

17 comments:

  1. Hi, thanks for your good example for navigation drawer,
    how to add searchview to this example?

    ReplyDelete
    Replies
    1. Hello,

      You can easily add the search. Just add the textwatcher in edittext, Then create a new list which contain the search content and then notify your adapter. I will work perfectly.

      Kind Regards,
      Deepshikha Puri

      Delete
  2. hello, how are you?
    thanks for your reply, to create new list inside main activity or new class?
    thanks and waiting for your reply.

    ReplyDelete
  3. Hello, How are you?
    I am new in android can you help and elaborate more for me.
    thanks and waiting for your reply.

    ReplyDelete
  4. Hi
    Thanks fr this useful tutorial, i m a beginner in Android. i want to know what if the drawer items are mix of expandable and non-expandable ? how to achieve that. Thanks in advance.

    ReplyDelete
  5. Hi Deepshikha Puri, how are you?
    I try put edit text to right of tvname and apply the following code under oncreate, but when i try to test the search the app closed given error message (unfortunately app has stop)below is the code, may i know how to correct this problem?
    thanks and waiting for your response.

    final EditText editText = (EditText) findViewById(R.id.editText);

    editText.addTextChangedListener(new TextWatcher() {

    @Override
    public void onTextChanged(CharSequence cs, int arg1, int arg2, int arg3) {
    // TODO Auto-generated method stub
    //You should use the adapter in NavigationDrawerFragment
    obj_adapter.getFilter().filter(cs);

    }

    @Override
    public void beforeTextChanged(CharSequence arg0, int arg1, int arg2,
    int arg3) {
    // TODO Auto-generated method stub

    }

    @Override
    public void afterTextChanged(Editable arg0) {
    // TODO Auto-generated method stub

    }
    });

    ReplyDelete
  6. Thanks for this example but i have problem like only some groups are expand and other are non-expand.so please tell me about how to customize expandable adapter....

    ReplyDelete
    Replies
    1. my problem is exactly like yours..waiting for some reply from this blog..if u get any code plz let me know..

      Delete
    2. Hello Guys,

      All the groups are expanded in this example. If you are getting the issue then send me video please so that I can rectify the problem and solve it ASAP.

      Thanks!
      Deepshikha puri

      Delete
  7. hello.thanks for your tutorial..im getting error in MainActivity this line....
    for (int i = 0; i < jsonArray_country.length(); i++)
    it shows unfortunately as soon as the app is launched....

    ReplyDelete
  8. hello.tanks for your tutorial.how remove all items CHINES meaning other no textview display for CHINES.since CHINES want for house.

    ReplyDelete
  9. hi Deepshikha thanks for this example....can i add up and down imageview in my navigation drower in country names ? means when india is open then that arrow shows up and if india is close then arraow show down

    ReplyDelete
  10. Hello, this is an excellent tutorial.

    I have a question, how can I add images to the Menu, and different images to the submenus.

    Thanks

    ReplyDelete
  11. actually i want to develop non-extendable list with this extendable listview, is that possible ,if possible how can i proceed with that ?

    ReplyDelete
  12. Good day, Deepshikha Puri

    Thank you for an amazing tutorial, I wish that I came across it sooner...

    I see that you get all your data from a Json file... is it possible to not use a data file but Firebase Database instead? and how would I go about it.

    Kind Regards

    Ben

    ReplyDelete
  13. can i do only one expanded item with other to having no childs?

    ReplyDelete