skip to Main Content

In Android Studio 2.1.2, if i create a default navigation activity I get this view:

enter image description here

Which uses the following activity_main.xml file:

<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:openDrawer="start">

    <include
        layout="@layout/app_bar_main"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <android.support.design.widget.NavigationView
        android:id="@+id/nav_view"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:fitsSystemWindows="true"
        app:headerLayout="@layout/nav_header_main"
        app:menu="@menu/activity_main_drawer" />

</android.support.v4.widget.DrawerLayout>

As you can see <android.support.design.widget.NavigationView/> uses app:menu="@menu/activity_main_drawer" for displaying list of menu defined in activity_main_drawer.xml file as follows:

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

    <group android:checkableBehavior="single">
        <item
            android:id="@+id/nav_camera"
            android:icon="@drawable/ic_menu_camera"
            android:title="Import" />
        <item
            android:id="@+id/nav_gallery"
            android:icon="@drawable/ic_menu_gallery"
            android:title="Gallery" />
        <item
            android:id="@+id/nav_slideshow"
            android:icon="@drawable/ic_menu_slideshow"
            android:title="Slideshow" />
        <item
            android:id="@+id/nav_manage"
            android:icon="@drawable/ic_menu_manage"
            android:title="Tools" />
    </group>

    <item android:title="Communicate">
        <menu>
            <item
                android:id="@+id/nav_share"
                android:icon="@drawable/ic_menu_share"
                android:title="Share" />
            <item
                android:id="@+id/nav_send"
                android:icon="@drawable/ic_menu_send"
                android:title="Send" />
        </menu>
    </item>

</menu>

Now my plan is to replace this menu list defined in activity_main_drawer.xml and instead use an ExpandableListView. Because I want my menu items to have subcategories, for example, menu item Cars will have sub category of Diesel, Petrol and Hybrid etc. I have done research and it appears no one has the exact working solution I need.

I looked here:

  1. The Open Tutorials
  2. Implement expandablelistview in navigation drawer activity made by android studio
  3. Android: 2 or more ExpandableListView inside Navigation Drawer
  4. How to create an expandable listView inside navigation drawer?

and the subsequent links mentioned there.

N.B: The links above mentions the use of ListView in navigation drawer which is no longer the case as Android Studio achieves this by using menu item using activity_main_drawer.xml.

Can someone please provide me an working example of this?
To re-iterate, I want an expandable list view inside the default navigation drawer activity. Ive gathered that I’ll need XML files and java class codes to get me the foundation I need to get started.

Thanks in advance. 🙂

EDIT: Final look mockup (excuse my photoshop skills)enter image description here

My current approach is to create a new layout ex_list as follows:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">
    <android.support.v4.widget.DrawerLayout
        android:id="@+id/drawer_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
       <ExpandableListView
            android:id="@+id/lvExp"
            android:layout_height="match_parent"
            android:layout_width="match_parent"/>

    </android.support.v4.widget.DrawerLayout>
</LinearLayout>

and edit activity_main.xml to

<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:openDrawer="start">

    <include
        layout="@layout/app_bar_main"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <android.support.design.widget.NavigationView
        android:id="@+id/nav_view"
        android:layout_width="240dp"
        android:layout_gravity = "start"
        android:layout_height="match_parent"

        android:fitsSystemWindows="true"
        app:headerLayout="@layout/nav_header_main">
        <include
            layout="@layout/ex_list"
            android:layout_height="wrap_content"
            android:layout_width="match_parent"/>

    </android.support.design.widget.NavigationView>


</android.support.v4.widget.DrawerLayout>

Which results to following layout:

enter image description here

and error message of

                                                                      java.lang.IllegalArgumentException: DrawerLayout must be measured with MeasureSpec.EXACTLY.
                                                                          at android.support.v4.widget.DrawerLayout.onMeasure(DrawerLayout.java:1036)
                                                                          at android.view.View.measure(View.java:18788)
                                                                          at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5951)
                                                                          at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1465)
                                                                          at android.widget.LinearLayout.measureVertical(LinearLayout.java:748)
                                                                          at android.widget.LinearLayout.onMeasure(LinearLayout.java:630)
                                                                          at android.view.View.measure(View.java:18788)
                                                                          at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5951)
                                                                          at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
                                                                          at android.support.design.widget.NavigationView.onMeasure(NavigationView.java:223)
                                                                          at android.view.View.measure(View.java:18788)
                                                                          at android.support.v4.widget.DrawerLayout.onMeasure(DrawerLayout.java:1104)
                                                                          at android.view.View.measure(View.java:18788)
                                                                          at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5951)
                                                                          at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
                                                                          at android.support.v7.widget.ContentFrameLayout.onMeasure(ContentFrameLayout.java:135)
                                                                          at android.view.View.measure(View.java:18788)
                                                                          at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5951)
                                                                          at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1465)
                                                                          at android.widget.LinearLayout.measureVertical(LinearLayout.java:748)
                                                                          at android.widget.LinearLayout.onMeasure(LinearLayout.java:630)
                                                                          at android.view.View.measure(View.java:18788)
                                                                          at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5951)
                                                                          at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
                                                                          at android.view.View.measure(View.java:18788)
                                                                          at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5951)
                                                                          at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1465)
                                                                          at android.widget.LinearLayout.measureVertical(LinearLayout.java:748)
                                                                          at android.widget.LinearLayout.onMeasure(LinearLayout.java:630)
                                                                          at android.view.View.measure(View.java:18788)
                                                                          at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5951)
                                                                          at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
                                                                          at com.android.internal.policy.PhoneWindow$DecorView.onMeasure(PhoneWindow.java:2643)
                                                                          at android.view.View.measure(View.java:18788)
                                                                          at android.view.ViewRootImpl.performMeasure(ViewRootImpl.java:2100)
                                                                          at android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java:1216)
                                                                          at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1452)
                                                                          at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1107)
                                                                          at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6013)
                                                                          at android.view.Choreographer$CallbackRecord.run(Choreographer.java:858)
                                                                          at android.view.Choreographer.doCallbacks(Choreographer.java:670)
                                                                          at android.view.Choreographer.doFrame(Choreographer.java:606)
                                                                          at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:844)
                                                                          at android.os.Handler.handleCallback(Handler.java:739)
                                                                          at android.os.Handler.dispatchMessage(Handler.java:95)
                                                                          at android.os.Looper.loop(Looper.java:148)
                                                                          at android.app.ActivityThread.main(ActivityThread.java:5417)
                                                                          at java.lang.reflect.Method.invoke(Native Method)
                                                                          at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
                                                                          at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)

What am I doing wrong?

ANSWER:

enter image description here

Thanks @Moulesh !!!

2

Answers


  1. This is the code for expandable list adapter:

    public class ExpandListAdapter extends BaseExpandableListAdapter {
    private Context _context;
    private List<String> _listDataHeader; // header titles
    // child data in format of header title, child title
    private HashMap<String, List<String>> _listDataChild;
    
    public ExpandListAdapter(Context context, List<String> listDataHeader,
                             HashMap<String, List<String>> listChildData) {
        this._context = context;
        this._listDataHeader = listDataHeader;
        this._listDataChild = listChildData;
    }
    
    @Override
    public Object getChild(int groupPosition, int childPosititon) {
        return this._listDataChild.get(this._listDataHeader.get(groupPosition))
                .get(childPosititon);
    }
    
    @Override
    public long getChildId(int groupPosition, int childPosition) {
        return childPosition;
    }
    
    @Override
    public View getChildView(int groupPosition, final int childPosition,
                             boolean isLastChild, View convertView, ViewGroup parent) {
    
        final String childText = (String) getChild(groupPosition, childPosition);
    
        if (convertView == null) {
            LayoutInflater infalInflater = (LayoutInflater) this._context
                    .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = infalInflater.inflate(R.layout.list_item, null);
        }
    
        TextView txtListChild = (TextView) convertView
                .findViewById(R.id.lblListItem);
    
        txtListChild.setText(childText);
        return convertView;
    }
    
    @Override
    public int getChildrenCount(int groupPosition) {
        return this._listDataChild.get(this._listDataHeader.get(groupPosition))
                .size();
    }
    
    @Override
    public Object getGroup(int groupPosition) {
        return this._listDataHeader.get(groupPosition);
    }
    
    @Override
    public int getGroupCount() {
        return this._listDataHeader.size();
    }
    
    @Override
    public long getGroupId(int groupPosition) {
        return groupPosition;
    }
    
    @Override
    public View getGroupView(int groupPosition, boolean isExpanded,
                             View convertView, ViewGroup parent) {
        String headerTitle = (String) getGroup(groupPosition);
        if (convertView == null) {
            LayoutInflater infalInflater = (LayoutInflater) this._context
                    .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = infalInflater.inflate(R.layout.list_group, null);
        }
    
        TextView lblListHeader = (TextView) convertView
                .findViewById(R.id.lblListHeader);
        lblListHeader.setTypeface(null, Typeface.BOLD);
        lblListHeader.setText(headerTitle);
    
        return convertView;
    }
    
    @Override
    public boolean hasStableIds() {
        return false;
    }
    
    @Override
    public boolean isChildSelectable(int groupPosition, int childPosition) {
        return true;
    }}
    

    In your activity:

         private void enableExpandableList() {
          listDataHeader = new ArrayList<String>();
          listDataChild = new HashMap<String, List<String>>();
        expListView = (ExpandableListView) findViewById(R.id.left_drawer);
    
        prepareListData(listDataHeader, listDataChild);
        listAdapter = new ExpandListAdapter(this, listDataHeader, listDataChild);
        // setting list adapter
        expListView.setAdapter(listAdapter);
    
        expListView.setOnGroupClickListener(new ExpandableListView.OnGroupClickListener() {
    
            @Override
            public boolean onGroupClick(ExpandableListView parent, View v,
                                        int groupPosition, long id) {
                // Toast.makeText(getApplicationContext(),
                // "Group Clicked " + listDataHeader.get(groupPosition),
                // Toast.LENGTH_SHORT).show();
                return false;
            }
        });
        // Listview Group expanded listener
        expListView.setOnGroupExpandListener(new ExpandableListView.OnGroupExpandListener() {
    
            @Override
            public void onGroupExpand(int groupPosition) {
                Toast.makeText(getApplicationContext(),
                        listDataHeader.get(groupPosition) + " Expanded",
                        Toast.LENGTH_SHORT).show();
            }
        });
    
        // Listview Group collasped listener
        expListView.setOnGroupCollapseListener(new ExpandableListView.OnGroupCollapseListener() {
    
            @Override
            public void onGroupCollapse(int groupPosition) {
                Toast.makeText(getApplicationContext(),
                        listDataHeader.get(groupPosition) + " Collapsed",
                        Toast.LENGTH_SHORT).show();
    
            }
        });
    
        // Listview on child click listener
        expListView.setOnChildClickListener(new ExpandableListView.OnChildClickListener() {
    
            @Override
            public boolean onChildClick(ExpandableListView parent, View v,
                                        int groupPosition, int childPosition, long id) {
                // TODO Auto-generated method stub
                // Temporary code:
    
                // till here
                Toast.makeText(
                        getApplicationContext(),
                        listDataHeader.get(groupPosition)
                                + " : "
                                + listDataChild.get(
                                listDataHeader.get(groupPosition)).get(
                                childPosition), Toast.LENGTH_SHORT)
                        .show();
                return false;
            }
        });}
    

    Method to create List with data:

       private void prepareListData(List<String> listDataHeader, Map<String,
      List<String>> listDataChild) {
    
    
        // Adding child data
        listDataHeader.add("Product1");
        listDataHeader.add("product2");
        listDataHeader.add("Product3");
    
        // Adding child data
        List<String> top = new ArrayList<String>();
        top.add("x1");
        top.add("x2");
        top.add("x3");
        top.add("x4");
        top.add("x5");
    
    
        List<String> mid = new ArrayList<String>();
        mid.add("y1");
        mid.add("y2");
        mid.add("y3");
    
        List<String> bottom = new ArrayList<String>();
        bottom.add("z1");
        bottom.add("z2");
        bottom.add("z3");
    
    
    
        listDataChild.put(listDataHeader.get(0), top); // Header, Child data
        listDataChild.put(listDataHeader.get(1), mid);
        listDataChild.put(listDataHeader.get(2), bottom);
    }
    

    this code in layout xml

    <?xml version="1.0" encoding="utf-8"?>
        <android.support.v4.widget.DrawerLayout 
         xmlns:android="http://schemas.android.com/apk/res/android"
         xmlns:app="http://schemas.android.com/apk/res-auto"
         xmlns:tools="http://schemas.android.com/tools"
         android:id="@+id/drawer_layout"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:fitsSystemWindows="true"
         tools:openDrawer="start">
    
    <include
        android:id="@+id/act_bar"
        layout="@layout/app_bar_main"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
    
    <android.support.design.widget.NavigationView
        android:id="@+id/nav_view"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:fitsSystemWindows="true"
        app:headerLayout="@layout/nav_header_main">
        <!--app:menu="@menu/activity_main_drawer"-->
    
        <ExpandableListView
            android:id="@+id/left_drawer"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="@dimen/nav_header_height"
            android:background="@color/Background"
            android:dividerHeight="0dp" />
    
    </android.support.design.widget.NavigationView>
    </android.support.v4.widget.DrawerLayout>
    

    xml for ExplistHeader list_group.xml

        <?xml version="1.0" encoding="utf-8"?>
            <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            android:paddingTop="10dp"
            android:padding="30dp"
            android:background="@color/Background">
    
            <TextView
                android:id="@+id/lblListHeader"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                android:paddingLeft="?
                android:attr/expandableListPreferredItemPaddingLeft"
                android:textSize="17dp"
                android:textColor="@color/colorTextPrimary" />    
            </LinearLayout>
    

    xml for Explistchild list_item.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="55dip"
            android:background="@color/Background"
            android:orientation="vertical" >
    
            <TextView
                android:id="@+id/lblListItem"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                android:textSize="17dip"
                android:paddingTop="5dp"
                android:paddingBottom="5dp"
                android:paddingLeft="?
                android:attr/expandableListPreferredChildPaddingLeft" />
            </LinearLayout>
    
    Login or Signup to reply.
  2. Download source code from here(Navigation drawer with expandablelistview in android)

     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;
    
    
    public class CountryAdapter extends BaseExpandableListAdapter {
        Context context;
        ArrayList<Model_country> al_country;
    
        public CountryAdapter(Context context, ArrayList<Model_country> 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;
        }
    
    
    }
    

    Thanks!

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search