I have a menu defined in xml:
<group android:checkableBehavior="single" android:id="@+id/group"> <item android:id="@+id/grades" android:icon="@drawable/ic_font_download_black_48dp" android:checked="false" android:title="Grades" > <menu> <item android:id="@+id/mp1" android:icon="@drawable/ic_looks_one_black_24dp" android:checked="false" android:title="MP1" /> <item android:id="@+id/mp2" android:icon="@drawable/ic_looks_two_black_24dp" android:checked="false" android:title="MP2" /> <item android:id="@+id/mp3" android:icon="@drawable/ic_font_download_black_48dp" android:checked="false" android:title="MP3" /> <item android:id="@+id/mp4" android:icon="@drawable/ic_font_download_black_48dp" android:checked="false" android:title="MP4" /> </menu> </item> <item android:id="@+id/schedule" android:icon="@drawable/ic_event_black_48dp" android:checked="false" android:title="Schedule" /> <item android:id="@+id/attendance" android:icon="@drawable/ic_assignment_ind_black_48dp" android:checked="false" android:title="Attendance" /> <item android:id="@+id/assignments" android:icon="@drawable/ic_assignment_black_48dp" android:checked="false" android:title="Assignments" /> <item android:id="@+id/studentInfo" android:icon="@drawable/ic_account_circle_black_48dp" android:checked="false" android:title="Student Details" /> </group> <group android:id="@+id/group2" android:checkableBehavior="single"> <item android:id="@+id/placeholder" android:icon="@drawable/ic_android_black_48dp" android:checked="false" android:title="Placeholder" /> <item android:id="@+id/placeholder2" android:icon="@drawable/ic_android_black_48dp" android:checked="false" android:title="Placeholder" /> </group>
which adds a submenu which looks like this:
However, I am unable to make this submenu look like this: (collapsable)
I now know that I need to implement an expandableListView, but I am not sure how this would fit in with the menu I have already created.
Any advice is appreciated
You can create it using custom ListView
.
See the code below activity_navigation_view.xml
<?xml version="1.0" encoding="utf-8"?> <android.support.v4.widget.DrawerLayout android:id="@+id/drawer_layout" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello World!" /> <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"> <ExpandableListView android:id="@+id/navigationmenu" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_marginTop="192dp" android:background="@android:color/white"> </ExpandableListView> </android.support.design.widget.NavigationView> </android.support.v4.widget.DrawerLayout>
The adapter for expandable list view is as follows.
ExpandableListAdapter.java
import android.content.Context; import android.graphics.Typeface; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseExpandableListAdapter; import android.widget.ExpandableListView; import android.widget.ImageView; import android.widget.TextView; import java.util.HashMap; import java.util.List; public class ExpandableListAdapter extends BaseExpandableListAdapter { private Context mContext; private List<ExpandedMenuModel> mListDataHeader; // header titles // child data in format of header title, child title private HashMap<ExpandedMenuModel, List<String>> mListDataChild; ExpandableListView expandList; public ExpandableListAdapter(Context context, List<ExpandedMenuModel> listDataHeader, HashMap<ExpandedMenuModel, List<String>> listChildData, ExpandableListView mView) { this.mContext = context; this.mListDataHeader = listDataHeader; this.mListDataChild = listChildData; this.expandList = mView; } @Override public int getGroupCount() { int i = mListDataHeader.size(); Log.d("GROUPCOUNT", String.valueOf(i)); return this.mListDataHeader.size(); } @Override public int getChildrenCount(int groupPosition) { int childCount = 0; if (groupPosition != 2) { childCount = this.mListDataChild.get(this.mListDataHeader.get(groupPosition)) .size(); } return childCount; } @Override public Object getGroup(int groupPosition) { return this.mListDataHeader.get(groupPosition); } @Override public Object getChild(int groupPosition, int childPosition) { Log.d("CHILD", mListDataChild.get(this.mListDataHeader.get(groupPosition)) .get(childPosition).toString()); return this.mListDataChild.get(this.mListDataHeader.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 false; } @Override public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) { ExpandedMenuModel headerTitle = (ExpandedMenuModel) getGroup(groupPosition); if (convertView == null) { LayoutInflater infalInflater = (LayoutInflater) this.mContext .getSystemService(Context.LAYOUT_INFLATER_SERVICE); convertView = infalInflater.inflate(R.layout.listheader, null); } TextView lblListHeader = (TextView) convertView .findViewById(R.id.submenu); ImageView headerIcon = (ImageView) convertView.findViewById(R.id.iconimage); lblListHeader.setTypeface(null, Typeface.BOLD); lblListHeader.setText(headerTitle.getIconName()); headerIcon.setImageResource(headerTitle.getIconImg()); return convertView; } @Override public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) { final String childText = (String) getChild(groupPosition, childPosition); if (convertView == null) { LayoutInflater infalInflater = (LayoutInflater) this.mContext .getSystemService(Context.LAYOUT_INFLATER_SERVICE); convertView = infalInflater.inflate(R.layout.list_submenu, null); } TextView txtListChild = (TextView) convertView .findViewById(R.id.submenu); txtListChild.setText(childText); return convertView; } @Override public boolean isChildSelectable(int groupPosition, int childPosition) { return true; } }
list_submenu.xml is as follows.
<?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:id="@+id/submenu" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="20dp" android:padding="10dp" android:textColor="#000000" android:textSize="18sp"/> </LinearLayout>
listheader.xml is as follows.
<?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="2dp" android:orientation="vertical"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginLeft="20dp" android:orientation="horizontal"> <ImageView android:id="@+id/iconimage" android:layout_width="50dp" android:layout_height="50dp" android:paddingBottom="10dp" android:paddingLeft="10dp" android:paddingTop="10dp"/> <TextView android:id="@+id/submenu" android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="10dp" android:textColor="#000000" android:textSize="20sp"/> </LinearLayout> </LinearLayout>
In your navigation view activity, set the adapter for the expandable list view. NavigationViewActivity.java
public class NavigationViewActivity extends AppCompatActivity { private DrawerLayout mDrawerLayout; ExpandableListAdapter mMenuAdapter; ExpandableListView expandableList; List<ExpandedMenuModel> listDataHeader; HashMap<ExpandedMenuModel, List<String>> listDataChild; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_navigation_view); final ActionBar ab = getSupportActionBar(); /* to set the menu icon image*/ ab.setHomeAsUpIndicator(android.R.drawable.ic_menu_add); ab.setDisplayHomeAsUpEnabled(true); mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout); expandableList = (ExpandableListView) findViewById(R.id.navigationmenu); NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view); if (navigationView != null) { setupDrawerContent(navigationView); } prepareListData(); mMenuAdapter = new ExpandableListAdapter(this, listDataHeader, listDataChild, expandableList); // setting list adapter expandableList.setAdapter(mMenuAdapter); expandableList.setOnChildClickListener(new ExpandableListView.OnChildClickListener() { @Override public boolean onChildClick(ExpandableListView expandableListView, View view, int i, int i1, long l) { //Log.d("DEBUG", "submenu item clicked"); return false; } }); expandableList.setOnGroupClickListener(new ExpandableListView.OnGroupClickListener() { @Override public boolean onGroupClick(ExpandableListView expandableListView, View view, int i, long l) { //Log.d("DEBUG", "heading clicked"); return false; } }); } private void prepareListData() { listDataHeader = new ArrayList<ExpandedMenuModel>(); listDataChild = new HashMap<ExpandedMenuModel, List<String>>(); ExpandedMenuModel item1 = new ExpandedMenuModel(); item1.setIconName("heading1"); item1.setIconImg(android.R.drawable.ic_delete); // Adding data header listDataHeader.add(item1); ExpandedMenuModel item2 = new ExpandedMenuModel(); item2.setIconName("heading2"); item2.setIconImg(android.R.drawable.ic_delete); listDataHeader.add(item2); ExpandedMenuModel item3 = new ExpandedMenuModel(); item3.setIconName("heading3"); item3.setIconImg(android.R.drawable.ic_delete); listDataHeader.add(item3); // Adding child data List<String> heading1 = new ArrayList<String>(); heading1.add("Submenu of item 1"); List<String> heading2 = new ArrayList<String>(); heading2.add("Submenu of item 2"); heading2.add("Submenu of item 2"); heading2.add("Submenu of item 2"); listDataChild.put(listDataHeader.get(0), heading1);// Header, Child data listDataChild.put(listDataHeader.get(1), heading2); } @Override public boolean onCreateOptionsMenu(Menu menu) { return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case android.R.id.home: mDrawerLayout.openDrawer(GravityCompat.START); return true; } return super.onOptionsItemSelected(item); } private void setupDrawerContent(NavigationView navigationView) { //revision: this don't works, use setOnChildClickListener() and setOnGroupClickListener() above instead navigationView.setNavigationItemSelectedListener( new NavigationView.OnNavigationItemSelectedListener() { @Override public boolean onNavigationItemSelected(MenuItem menuItem) { menuItem.setChecked(true); mDrawerLayout.closeDrawers(); return true; } }); } }
ExpandedMenuModel class contains menu item details as follow.
ExpandedMenuModel.java
public class ExpandedMenuModel { String iconName = ""; int iconImg = -1; // menu icon resource id public String getIconName() { return iconName; } public void setIconName(String iconName) { this.iconName = iconName; } public int getIconImg() { return iconImg; } public void setIconImg(int iconImg) { this.iconImg = iconImg; } }
[Side note]:
Don't put import android.widget.ExpandableListAdapter;
in NavigationViewActivity.java. This mistake can happen if you resolve import by Alt+Enter before create the file ExpandableListAdapter.java.
Put compile 'com.android.support:design:23.3.0' in app's build.gradle, it's for "NavigationView" and its "import android.support.design.widget.NavigationView;" After that (Might require rebuild first) you can do Alt-Enter to resolve import.
The file hierarchy should look like (3 .java and 3 .xml from above):
The output screenshot:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With