1

In my app I'm loading the navigation drawer with the following .xml. In the first group I have an item for current_device and other_device. There is potential to have several other devices listed here, but this is determined at runtime with an api call. Is there a way to dynamically add items to this .xml? Or a better way to do this. c

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

<group
    android:id="@+id/nav_devices_group"
    android:checkableBehavior="single">

    <item
        android:id="@+id/nav_current_device"
        android:icon="@drawable/common_full_open_on_phone"
        android:title="@string/nav_current_device" />

    <item
        android:id="@+id/nav_other_device"
        android:icon="@drawable/common_full_open_on_phone"
        android:title="@string/nav_devices" />

</group>

<group>
    <item
        android:id="@+id/nav_settings"
        android:icon="@drawable/ic_setting_dark"
        android:title="@string/nav_settings" />

    <item
        android:id="@+id/nav_about"
        android:icon="@android:drawable/ic_dialog_info"
        android:title="@string/nav_about" />
</group>

</menu>

The nav drawer layout is below:

<?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/activity_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/menu_nav_drawer" />

</android.support.v4.widget.DrawerLayout>
ENG618
  • 1,012
  • 1
  • 13
  • 31

2 Answers2

1

Here's the code to add an item.

mNavigationView = (NavigationView) context.findViewById(R.id.navigationView);
Menu menu = mNavigationView.getMenu();
SubMenu devicesMenu = menu.addSubMenu(Menu.NONE, DEVICES_MENU_ID, Menu.NONE, "Devices");
//You get your deviceId (nexus5Id, nexus6Id and so on) from your API call
//You should see deviceId in your code, from a loop or network callback
//in place of my hardcoded devices ids
devicesMenu.add(DEVICES_MENU_ID, nexus5Id, "Nexus 5");
devicesMenu.add(DEVICES_MENU_ID, nexus6Id, "Nexus 6");
devicesMenu.add(DEVICES_MENU_ID, nexus5XId, "Nexus 5X");
devicesMenu.add(DEVICES_MENU_ID, nexus6PId, "Nexus 6P");

To get the menu item, to set it checked, change it's icon or anything:

MenuItem device = devicesMenu.find(deviceId);
devicesMenu.setChecked(true);

To remove an item:

devicesMenu.remove(deviceId);

Note that SubMenu extends Menu. I suggest you to check the documentation of Menu and MenuItem.

EDIT

As your ids aren't suitable for int format required by MenuItems, I think you should add a ScrollView/NestedScrollView in place of your NavigationMenu, add classic TextView with drawableLeft for non group items, and exandable View (LinearLayout for example) with group TextView, which expand when clicked, showing a RecyclerView containing all your devices.

This way, you can use a custom adapter and manage your ids the way you want (the best practice however is to use long ids in RecyclerView (and legacy ListView)).

However, I'm not sure that adding all the devices in the NavigationDrawer (be it standard API with menus, or with a RecyclerView) is a good practice, as the devices could be very long, right? For a large devices collection, I would use a standard non grouped "Devices" item in my NavigationDrawer, and then, showing the user either a searchbox, or a list with devices.

Louis CAD
  • 10,965
  • 2
  • 39
  • 58
  • where you have `nexus5ID`, I would be using something like `d2bc6f797fd07614`. However it is looking for 'int itemID'. Can I convert the actual device id to an int? – ENG618 Oct 07 '15 at 07:20
  • I have this `deviceMenu.add(R.id.nav_devices, Integer.parseInt("d2bc6f797fd07614"), Menu.NONE, "Nexus");` but it's causing an exception: `Caused by: java.lang.NumberFormatException: Invalid int: "d2bc6f797fd07614"` – ENG618 Oct 07 '15 at 07:24
  • I think you can't use Menus if you have such ids, as converting it to bytes, and casting would probably not fit in int capacity, you would require a long, but it would be hacky, and Menus don't support it – Louis CAD Oct 07 '15 at 07:26
  • Okay, I just made it work with a simpler int, final question. How would I position this at the top of the menu? Right now the devices menu is coming in on the bottom, under my settings – ENG618 Oct 07 '15 at 07:32
  • I made en edit to my answer, but I don't know if your devices collection would be large, or not, tell me please :) – Louis CAD Oct 07 '15 at 07:38
  • Use the order parameter in addSubMenu . If you set it to 0, it should show first if the rest of your menu items aren't at 0 too. – Louis CAD Oct 07 '15 at 07:41
  • No the devices should never be more then 5. Will typically be 2-3 – ENG618 Oct 07 '15 at 07:43
  • That's fine for NavigationDrawer usage ;) If your app can partially work offline, you should cache the devices to prevent having to fetch the devices info over the network each time your activity is restarted. I would improve performance (many people have slow internet), and would lighten API server traffic – Louis CAD Oct 07 '15 at 07:47
0

From: How to programmatically add a submenu item to the new material design android support library

Adding a dynamic menu to NavigationView is currently bug on Design Support library. And I have report it to android bug source tracking. So wait till the bug will fixed. But if you want the temporary solution you can do it. First add your dynamic menu ..

    navView = (NavigationView) findViewById(R.id.navView);
    Menu m = navView.getMenu();
    SubMenu topChannelMenu = m.addSubMenu("Top Channels");
    topChannelMenu.add("Foo");
    topChannelMenu.add("Bar");
    topChannelMenu.add("Baz");

After adding your menu just write below code ..

    MenuItem mi = m.getItem(m.size()-1);
    mi.setTitle(mi.getTitle());

It's currently hacky solution. But work for me ...

Community
  • 1
  • 1
cw fei
  • 1,534
  • 1
  • 15
  • 33