Dynamic Menus in NavigationView - android

I have this Layout:
<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_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<!-- The ActionBar -->
<include
layout="#layout/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<!-- The main content view -->
<FrameLayout
android:id="#+id/flContent"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
<!-- The navigation drawer -->
<android.support.design.widget.NavigationView
android:id="#+id/nvView"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:background="#android:color/white"
app:menu="#menu/drawer_menu"
app:headerLayout="#layout/nav_header"/>
So, looking that in NavigationView we have the attribute:
app:menu="#menu/drawer_menu"
And I have this XML id menu folder.
I wanna make dynamic menus, ie, in code I should mount the 'MenuItem' objects and set into NavigationView.
Is this correct?
Is this best pratice?
Is this possible?
Note: My code is working with 'static drawer_menu', I want to improve it.
I'm waiting.
[EDIT]
I make it:
Menu menu = nvDrawer.getMenu();
for (KSMenuItem kmi : menus.values()) {
if (menu.size() == 0) {
menu.add(kmi.getId());
}
if (menu.getItem(kmi.getId()) == null) {
menu.add(kmi.getId());
}
MenuItem mi = menu.getItem(kmi.getId());
mi.setIcon(kmi.getIcon());
mi.setTitle(kmi.getTittle());
}
But this error happened:
06-27 15:26:15.538 15335-15335/? E/AndroidRuntime﹕ FATAL EXCEPTION: main
Process: com.example.sticdev30.newdrawer, PID: 15335
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.sticdev30.newdrawer/com.example.sticdev30.newdrawer.MainActivity}: android.content.res.Resources$NotFoundException: String resource ID #0x1
KSMenuItem is a POJO with my menu data. In kmi.id I informed incremental integers...
I'm waitning

You can re-inflate NavigationViewat runtime with 2 lines of code using public method inflateMenu. In this example i re-inflate with new_navigation_drawer_items.xml
navigationView.getMenu().clear(); //clear old inflated items.
navigationView.inflateMenu(R.menu.new_navigation_drawer_items); //inflate new items.

You can add menus dynamically by following steps :
Step1. Obtain menu object from Navigation View NavigationView.getMenu()
Step2. Add any item to the menu using Menu.add()

We can dynamically add/remove menu items.
Suppose we have this menu items `
<group android:checkableBehavior="single">
<item
android:id="#+id/nav_home"
android:icon="#mipmap/home_icon_x48"
android:title="Home" />
<item
android:id="#+id/nav_part_catalouge"
android:icon="#mipmap/catalogue_icon_x48"
android:title="Parts Catalogue" />
<item
android:id="#+id/nav_favourite"
android:icon="#mipmap/my_favourate_x48"
android:title="My-Favourite" />\
<item
android:id="#+id/nav_opencarrequest"
android:icon="#mipmap/cart_request"
android:title="Cart-Request" />
<item
android:id="#+id/nav_setting"
android:icon="#mipmap/settings_x48"
android:title="Settings" />
</group>
<item android:title="">
<menu>
<item
android:id="#+id/nav_logout"
android:icon="#mipmap/logout_icon_x48"
android:title="Logout" />
</menu>
</item>
`
In Activity we can add or remove menuitems based on our condition
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);// your activity layout here
NavigationView navigationView= (NavigationView) findViewById(R.id.nav_view); // navigation view which holds menu items
navigationView.setNavigationItemSelectedListener(this);
if(yourCondition){
navigationView.getMenu().getItem(0).setVisible(false); //if you want to hide first item
navigationView.getMenu().getItem(1).setVisible(true); // if you want to show second menu item should be visible
}
}
Hope it will help.

Seems like kmi.getId() returns int(or long).
But Menu.add(int) adds menu with title from the given string resources, which is usually represented as R.string.something, and not for usual integer values.
Menu.add(CharSequence) does add menu with title of CharSequence, so you need to do some int-to-string conversion like menu.add(kmi.getId() + "");

Related

Accessing and adding items to Spinner

I added a spinner to menu and I would like to add items dynamically to the spinner. But the problem is that Spinner is pretty deep in layouts.
I have a view of main action with navigation -> that includes main action view and contains NavigationView -> NavigationView has menu -> menu contains items -> one of items contains another menu and first item of that menu is Spinner.
Is there any better way to add dropdown to the menu? If not, how do I access the spinner?
Thanks for the help
Code:
MainActivity.kt:
class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelectedListener, AdapterView.OnItemSelectedListener{
private lateinit var activities: Spinner
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main_with_nav)
activities = this.findViewById(R.id.menu_activity_select) //--- throws exception
activity_main_with_nav.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"
tools:openDrawer="start"
android:theme="#style/Theme.AppCompat.Light.NoActionBar">
<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"
app:headerLayout="#layout/nav_main"
app:menu="#menu/main_menu" />
</android.support.v4.widget.DrawerLayout>
main_menu.xml :
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="#+id/menu_activity"
android:title="#string/menu_activity">
<menu>
<item android:id="#+id/menu_activity_select"
android:title="#string/menu_activity_select"
app:actionViewClass="android.widget.Spinner"
/> <!-- this is the spinner I am looking for -->
<item android:id="#+id/menu_activity_activate_devices"
android:icon="#android:drawable/ic_dialog_dialer"
android:title="#string/menu_activity_activate_devices" />
<item android:id="#+id/menu_activity_camera"
android:icon="#android:drawable/ic_menu_camera"
android:title="#string/menu_activity_camera" />
</menu>
</item>
<group>
<item android:id="#+id/menu_scan_qr"
android:icon="#drawable/ic_codigo_qr"
android:title="#string/menu_scan_qr" />
<item android:id="#+id/menu_calendar"
android:icon="#android:drawable/ic_menu_month"
android:title="#string/menu_calendar" />
<item android:id="#+id/menu_settings"
android:icon="#android:drawable/ic_menu_manage"
android:title="#string/menu_settings" />
</group>
</menu>
It should not matter how deep the spinner is in the layout. If you are calling findViewById() in the correct view hierarchy, it should give you the instance of spinner. Once you get the instance of the spinner you just need to set the adapter with items. If you want to add items dynamically just add the new item in the whatever data structure have you used for the adapter. After then call notifyDataSetChanged() on the adapter.

How to place element in Navigation drawer in Android

I want to do a navigation drawer with icons and text displayed like this : image with icon display in block
My navigation drawer is :
<android.support.design.widget.NavigationView
android:id="#+id/navigationView"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:background="#drawable/drawer_background"
app:headerLayout="#layout/navigation_drawer_header"
app:itemIconTint="#color/white"
app:itemTextColor="#color/white"
app:menu="#menu/navigation_drawer_items" />
And my menu is like this :
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<group android:checkableBehavior="single">
<!-- todo: une page d'accueil avec les plus grosse cote, une preview du bilan (cardview? ...)-->
<item
android:id="#+id/navItemHome"
android:icon="#drawable/ic_home_black_24dp"
android:title="#string/action_home"/>
<item
android:id="#+id/navItemParisTermine"
android:icon="#drawable/ic_home_black_24dp"
android:title="#string/actionParisTermine"/>
<item
android:id="#+id/navItemAffiliation"
android:icon="#drawable/ic_home_black_24dp"
android:title="#string/actionAffiliation"/>
<item
android:id="#+id/navItemBilan"
android:icon="#drawable/ic_home_black_24dp"
android:title="#string/actionBilan"/>
<item
android:id="#+id/navItemContactDeveloppeur"
android:icon="#drawable/ic_home_black_24dp"
android:title="#string/actionContactDeveloppeur"/>
</group>
</menu>
Sorry for my english and thanks for your attention!
Instead of using a menu in your navigation drawer, create a custom layout
<android.support.design.widget.NavigationView
android:id="#+id/navigation"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
// CREATE YOUR LAYOUT HERE
</LinearLayout>
I hope you got it.
Don't worry about your English, no one should make fun when someone is learning a new language, it just means they know another one
Menu is quite limited on customization. In this case you would probably need to get rid of menu at all.
To do this remove this line:
app:menu="#menu/navigation_drawer_items"
You can rely on navigation drawer header and implement custom view with icons as you show in example.
Your Navigation View has this line:
app:headerLayout="#layout/navigation_drawer_header"
So go to navigation_drawer_header and apply custom layout to it.

Get subview of loaded view (group inside a drawer)

I have a drawer with actions in a group, file a list of files I want to dynamically put in another group. My main activity has this layout:
<?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">
<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>
Then the loaded NavigationView is:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" android:id="#+id/test_id">
<group android:checkableBehavior="single" android:id="#+id/group_file_list">
<item
android:id="#+id/file1"
android:icon="#drawable/ic_menu_gallery"
android:title="File 1"/>
...
</group>
<item android:title="Actions">
<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>
When I try to get the group where the files are to later add the Items dynamically, all of these return null:
findViewById(R.id.group_file_list); // returns null
View navView = findViewById(R.id.nav_view); // works
navView.findViewById(R.id.group_file_list); // returns null
navView.findViewById(R.id.test_id); // returns null
And yes, I'm calling this after setContentView(). I also tried inside onStart()
Any ideas?
Use this to add items to your drawer:
NavigationView navView = findViewById(R.id.nav_view);
navView.getMenu().add(...);
Or, to add to a group, do this:
navView.getMenu().addSubMenu(Menu.NONE, Menu.NONE, Menu.NONE, groupName).add(...);
See NavigationView and Menu
Those are menu items and not views. You get them by using the options menu
Menu optionsMenu;
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
// store the menu to var when creating options menu
optionsMenu = menu;
}
Then you can find the item you want
MenuItem item = optionsMenu.findItem(R.id.test_id);

How to position menu items in Navigation View?

My question is related to recently released Navigation View from Design Support Library.
I want to position Log In at the bottom of the Navigation View, how I can do this?
My menu XML right now, look like this :
<?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/navigation_sub_item_1"
android:icon="#drawable/ic_action_event"
android:title="#string/home" />
<item
android:id="#+id/navigation_sub_item_2"
android:icon="#drawable/ic_action_person"
android:title="#string/profile" />
<item
android:id="#+id/navigation_sub_item_3"
android:icon="#drawable/ic_action_labels"
android:title="#string/tags" />
<item
android:id="#+id/navigation_sub_item_4"
android:icon="#drawable/ic_action_settings"
android:title="#string/log_in" />
</group>
</menu>
Here is my layout :
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:background="#color/white_1000">
<include
android:id="#+id/toolbar"
layout="#layout/toolbar" />
<android.support.v4.widget.DrawerLayout
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#id/toolbar">
<FrameLayout
android:id="#+id/content_frame"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
<android.support.design.widget.NavigationView
android:id="#+id/main_drawer"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
app:headerLayout="#layout/drawer_header"
app:menu="#menu/drawer_menu" />
</android.support.v4.widget.DrawerLayout>
</RelativeLayout>
Do you want your "Log In" item to be fixed at the bottom of the Navigation View?
You can do that by nesting additional views/layouts within NavigationView. NavigationView extends FrameLayout, so you can wrap it around child views.
I posted more information on NavigationView footers here. Also see the other answers in that post for more layout options.
Edit
FYI: If you use the "fixed footer" approach, you are basically removing the footer item (e.g. "Log In" in your example) from the menu. That means you have to implement click and other handlers yourself.
I think navigation menu works like a listview. So Items will be placed in a list.
If you want one item to be placed at the bottom, you can customise within the NavigationView Tag in layout xml

Android Lollipop, add popup menu from title in toolbar

I'm unable to see how adding a popup menu from the title is accomplished like is shown in many of the material design examples. Any help would be much appreciated.
You're going to need to add a Spinner to the Toolbar:
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_height="?attr/actionBarSize"
android:layout_width="match_parent"
android:background="?attr/colorPrimary">
<Spinner
android:id="#+id/spinner_nav"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</android.support.v7.widget.Toolbar>
You will then need to disable the default title:
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayShowTitleEnabled(false);
You can then retrieve and setup the Spinner as needed in your Activity/Fragment.
I came across this question while I was trying to find a solution to prevent the popup to overlay the spinner and I would like to leave here an alternative solution to this question as its possible to add the spinner to the toolbar using the menu.xml as well
activity_main.xml
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorAccent" />
</android.support.design.widget.AppBarLayout>
<!-- Other layout widgets -->
</LinearLayout>
menu_main.xml
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="#+id/spinner"
android:title="Spinning"
app:actionViewClass="android.widget.Spinner"
app:showAsAction="always" />
<!-- Other items -->
</menu>
Your Activity
It will be necessary to override the onCreateOptionMenu() method, then use getMenuInflater() to inflate the menu file created earlier.
You will also need to get the Spinner item and set an adapter to it as you would normally do.
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main, menu);
//Get Spinner item from menu
MenuItem spinnerMenuItem = menu.findItem(R.id.spinner);
final Spinner spinner = (Spinner) MenuItemCompat.getActionView(spinnerMenuItem);
//Set adapter whichever way you prefer (from the resource or manually)
final ArrayAdapter<CharSequence> spinnerAdapter = ArrayAdapter
.createFromResource(this, R.array.items_array, android.R.layout.simple_spinner_dropdown_item);
spinnerAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(spinnerAdapter);
return true;
}
Style.xml
Finally, if you want to customize your spinner
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="android:spinnerStyle">#style/spinner_style</item>
</style>
<style name="spinner_style" parent="Widget.AppCompat.Spinner">
<item name="android:dropDownVerticalOffset">40dip</item>
<!--<item name="android:dropDownHorizontalOffset">0dip</item>-->
<item name="overlapAnchor">false</item>
<!--Other customizations-->
</style>

Categories

Resources