How to generate a Dynamic Menu with NavigationView that contains a notification counter?
I'm developing an Android app that contains a menu that is dynamically generated, so the menu generates it programmatically:
private void cargarAvisosMenu()
{
// Menu
final Menu menu = this.mNavigationView.getMenu();
// Carga de datos
CentroSelection selection = new CentroSelection();
CentroCursor cur = selection.query(getApplicationContext().getContentResolver());
// Recorro el cursor de centros
while (cur.moveToNext()) {
boolean avisosTipoA = false;
boolean avisosTipoB = false;
Centro c = Centro.getFromCursor(cur);
if (c.getIsTipoAVisible() && c.getComponenteTipoA().getControlesTipoAPendientes() > 0) {
avisosTipoA = true;
}
if (c.getIsTipoBVisible() && c.getComponenteTipoB().getControlesTipoBPendientes() > 0){
avisosTipoB = true;
}
if (avisosTipoA || avisosTipoB) {
// Añado la sección y los items.
final SubMenu subMenu = menu.addSubMenu(c.getNombre());
if (avisosTipoA) {
subMenu.add("TipoA").setIcon(R.drawable.ic_tipoA);
}
if (avisosTipoB) {
subMenu.add("TipoB").setIcon(R.drawable.ic_tipoB);
}
}
}
}
My intention is to add a counter that indicates the number of notifications (gmail-style).
According to the documentation this is possible, either through an xml menu, using the attribute app:actionLayout
, or using the function MenuItemCompat.setActionView()
. Since the menu I am developing is dynamic, I have opted for the second option, so that the code would look like this:
private void cargarAvisosMenu()
{
// Menu
final Menu menu = this.mNavigationView.getMenu();
// Carga de datos
CentroSelection selection = new CentroSelection();
CentroCursor cur = selection.query(getApplicationContext().getContentResolver());
// Recorro el cursor de centros
while (cur.moveToNext()) {
boolean avisosTipoA = false;
boolean avisosTipoB = false;
Centro c = Centro.getFromCursor(cur);
if (c.getIsTipoAVisible() && c.getComponenteTipoA().getControlesTipoAPendientes() > 0) {
avisosTipoA = true;
}
if (c.getIsTipoBVisible() && c.getComponenteTipoB().getControlesTipoBPendientes() > 0){
avisosTipoB = true;
}
if (avisosTipoA || avisosTipoB) {
// Añado la sección y los items.
final SubMenu subMenu = menu.addSubMenu(c.getNombre());
if (avisosTipoA) {
subMenu.add("TipoA").setIcon(R.drawable.ic_tipoA);
}
if (avisosTipoB) {
// subMenu.add("TipoB").setIcon(R.drawable.ic_tipoB);
int itemId = subMenu.add("TipoB").getItemId();
View menuItem = MenuItemCompat.setActionView(subMenu.findItem(itemId), R.layout.menu_notificaciones).getActionView();
((ImageView) menuItem.findViewById(R.id.ivMenuNotificaciones)).setBackground(getDrawable(R.drawable.ic_barcode));
((TextView) menuItem.findViewById(R.id.tvMenuNotificaciones)).setText("TipoB");
((TextView) menuItem.findViewById(R.id.tvContadorNotificaciones)).setText("100");
}
}
}
}
And the file " menu_notifications.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:paddingLeft="16dp"
android:paddingRight="16dp"
android:orientation="horizontal">
<ImageView
android:id="@+id/ivMenuNotificaciones"
android:layout_width="64dp"
android:layout_height="match_parent" />
<TextView
android:id="@+id/tvMenuNotificaciones"
android:layout_width="wrap_content"
android:layout_height="match_parent" />
<TextView
android:id="@+id/tvContadorNotificaciones"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="right"/>
</LinearLayout>
However the menu does not load the "menu_notifications"view.
2 answers
I have finally fixed the problem by creating the menu manually, by entering a ListView
inside the NavigationView
component.
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/drawer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@+id/toolbar_actionbar"
android:fitsSystemWindows="true">
<!-- Contenido principal -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:theme="@style/ThemeOverlay.AppCompat.Dark"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />
<FrameLayout
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="true" />
</LinearLayout>
<!-- Menú Deslizable -->
<android.support.design.widget.NavigationView
android:id="@+id/nvMenu"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:background="@android:color/white"
android:fitsSystemWindows="true">
<!-- Menú Deslizable basado en ListView -->
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
android:id="@+id/left_drawer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white"
android:cacheColorHint="@android:color/transparent"
android:choiceMode="singleChoice"
android:divider="@android:color/transparent"
android:dividerHeight="0dp" />
</FrameLayout>
</android.support.design.widget.NavigationView>
</android.support.v4.widget.DrawerLayout>
If I'm not mistaken, this is the mode that was used in the past for menu development. I am aware that it is not the solution I was looking for, however I cannot find the way to add the counter by code directly to the NavigationView
control.
According to setActionView
the action will be replaced when this item is displayed as an action within the parent.
You need to indicate this action. You can do this using setShowAsAction
. This describes when this item can be displayed.