Reputation: 11352
I am using a DrawerLayout
on my Android app which works fine but I am having problems with the menu itself, where I want to have a collapsible section and some static items in the menu.
The exact layout I want to achieve is like this:
Drawer Title
-> Expandable List
Menu Item 1
Menu Item 2
And when the Expandable list is open to have something like this:
Drawer Title
-> Expandable List
Expandable List Item 1
Expandable List Item 2
Menu Item 1
Menu Item 2
The problem I have is that the menu doesn't seem to sit in the flow of the view like other elements do, so if I have my ExpandableListView
inside the NavigationView
that contains the menu, it opens over the other menu items and there doesn't seem to be a way to move them.
To try and address this I have moved the ExpandableListView
into a separate layout that provides the header for the menu. This now draws everything correctly but I can't open the list view any more, which is definitely a problem. In fact it does open - or at least the onGroupExpandListener
is triggered - but although the height of the header is set to wrap_content
and I invalidate
it on expand and collapse, the size of the header remains resolutely the same. To work around this I am manually changing it's size in the onGroupExpandListener
and onGroupCollapseListener
as follows.
In my layout I have a NavigationView like this:
<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:menu="@menu/drawer_view" >
</android.support.design.widget.NavigationView>
The header looks like this:
<LinearLayout
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:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<RelativeLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="70dp"
android:background="@color/colorPrimary" >
<ImageView
android:layout_width="70dp"
android:layout_height="70dp"
android:padding="10dp"
app:srcCompat="@drawable/main_icon" />
<TextView
android:id="@+id/drawer_header"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:layout_gravity="left|start|center"
android:layout_marginStart="70dp"
android:paddingStart="5pt"
android:text="Options"
android:textColor="#FFFFFF"
android:textSize="16pt"
android:textStyle="bold" />
</RelativeLayout>
<ExpandableListView
android:id="@+id/menu_expandable_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom" >
</ExpandableListView>
</LinearLayout>
In my code, I am currently setting up the ExpandableListView ( complete with a bunch of superfluous hacks because I'm trying to figure out the problem ) like this:
private void setOptionsMenuItems(final NavigationView menuContainer) {
final View v = menuContainer.inflateHeaderView(R.layout.drawer_header);
final ExpandableListView optionsMenu = (ExpandableListView) v.findViewById(R.id.menu_expandable_list);
final MyExpandableListAdapter adapter = new MyExpandableListAdapter(this, allTheItems );
optionsMenu.setAdapter(adapter);
optionsMenu.setOnChildClickListener(new ExpandableListView.OnChildClickListener() {
@Override
public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) {
setCurrentItem(allTheItems[childPosition]);
return true;
}
});
optionsMenu.setOnGroupExpandListener(new ExpandableListView.OnGroupExpandListener() {
@Override
public void onGroupExpand(int groupPosition) {
v.setMinimumHeight(v.getChildAt(0).getHeight() + adapter.getOpenHeight());
v.invalidate();
}
});
optionsMenu.setOnGroupCollapseListener(new ExpandableListView.OnGroupCollapseListener() {
@Override
public void onGroupCollapse(int groupPosition) {
v.setMinimumHeight(v.getChildAt(0).getHeight() + adapter.getClosedHeight());
v.invalidate();
}
});
}
What this version of the code does is to enlarge and shrink the header correctly when the group is opened or closed ( adapter.getOpenHeight()/getClosedHeight()
gives you the dimension you might expect ) but the actual child items never get rendered. Doing the same enlargement in an onGroupClickListener
is no different, although I suspect that the child elements are being culled from the view because the layout system assumes they are invisible, rather than the view being resized. If I manually make the header taller, so that everything is in view when the ExpandableList is expanded, it opens and closes as normal but obviously this does not allow me to move the other menu items up and down, which is the whole point.
This all seems inordinately complex for what must be a common use case so if I am taking completely the wrong approach here please let me know. All I want is for the first item in my menu to be an ExpandableList and for the other menu items to be regular menu items that move down when the the ExpandableList is opened and move back up when it is closed.
What do I need to do to have a working collapsible list of options in my menu?
Edit: With some more time on this, what I think is happening is that the list is bypassing drawing the new sections because it has measured that there is no visible room for them - although the resize can be triggered from the onGroupClickListener
the actual change in visible size doesn't occur until the next drawing pass, so when the base ListView tests to see whether there is room to write the list, it is coming up false.
Upvotes: 1
Views: 133
Reputation: 11352
I did not find a way to do this using a conventional menu- instead the solution I came to was adding my other menu items as ExpandableListView
groups so they simply appear at the top level of the list view. This allowed me to create the effect I was looking for, at the cost of not using menus the 'correct' way.
Upvotes: 1