I have the following main menu drawer, where the "Home button" is static, but the elements under "Read groups" are dynamically added. As you can see, the Home menu is properly checked (selected).
The groups all navigate to the same fragment (GroupsShowFragment), but with different parameters. The problem is, that if I navigate to such a group, the menu item selection is not updated (the Home selection even stays active).
Below the drawer_menu.xml code:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:showIn="navigation_view"
>
<group android:checkableBehavior="single">
<item
android:id="#+id/menu_nav_home"
android:icon="#drawable/ic_action_home"
android:title="Home" />
</group>
<group android:checkableBehavior="single" android:id="#+id/groups_sub_holder">
<item
android:id="#+id/groups_holder"
android:title="Read groups">
<menu>
</menu>
</item>
</group>
<item android:title="Controls">
<menu>
<group android:checkableBehavior="single">
<item
android:id="#+id/menu_nav_group_add"
android:icon="#drawable/ic_action_add_group"
android:title="#string/fragment_title_groups_add" />
<item
android:id="#+id/menu_nav_settings"
android:icon="#drawable/ic_action_settings"
android:title="Settings" />
</group>
</menu>
</item>
</menu>
The code used to dynamicly add the read groups (data is coming from a Room database):
// Add menu source: https://stackoverflow.com/a/31722855/1175881
val navigationView: NavigationView = findViewById <NavigationView> (R.id.nav_view)
val menu: Menu = (navigationView.menu.findItem(R.id.groups_holder)).subMenu
menu.clear()
// adding a section and items into it
val allGroups: List<Groups> = GroupsManager.getAllGroups()
allGroups.forEach{
it.uid?.let { it1 -> menu.add(0, it1, 0, it.name) }
}
And the code which is handling the "navigation":
private fun handleNavigateTrigger(menuId: Int){
when(menuId) {
R.id.menu_nav_home -> {
homeFragment = HomeFragment()
showFragment(homeFragment)
}
R.id.menu_nav_settings -> {
settingsFragment = SettingsFragment()
showFragment(settingsFragment)
}
R.id.menu_nav_group_add -> {
groupsAddFragment = GroupsAddFragment()
showFragment(groupsAddFragment)
}
else -> {
groupsShowFragment = GroupsShowFragment.newInstance(menuId)
showFragment(groupsShowFragment)
val navigationView: NavigationView = findViewById <NavigationView> (R.id.nav_view)
Log.e("handleNavigateTrigger", "setCheckedItem($menuId)")
navigationView.setCheckedItem(menuId)
}
}
_drawerLayout.closeDrawer(GravityCompat.START)
}
private fun showFragment(fragment: androidx.fragment.app.Fragment){
supportFragmentManager
.beginTransaction()
.replace(R.id.frame_layout, fragment)
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
.commit()
}
The log does show the correct id's (at least the correct integers) used, so I'm a bit lost here. I've added the group with android:checkableBehavior="single" like this, even as whole menu parent, but to no avail. I'm feeling like I miss one small but very important step, but can't find what that is..
This is a self-answer, but wanted to share the found solution for anybody in the future (can only accept this answer in 2 days, so I'll get back to do that)
I've finally stumbled on this SO answer by Danial B.
Using only the setChecked resulted in a partial (but not sufficient and correctly working) checked menu item. I had to make sure that the menu item was checkable with setCheckable. This resulted in the following code for me:
val navigationView: NavigationView = findViewById <NavigationView> (R.id.nav_view)
val groupItem: MenuItem = navigationView.menu.findItem(menuId)
groupItem.isCheckable = true
groupItem.isChecked = true
Related
I want to add click event when I click on one of the item in navigation drawer, I have used onNavigationItemSelected method but it's not working, Any help?
override fun onNavigationItemSelected(item: MenuItem): Boolean {
TODO("Not yet implemented")
val id = item.itemId
if (id == R.id.nav_signout) {
Toast.makeText(this, "Sign out", Toast.LENGTH_SHORT).show()
}
return true
}
drawer.xml
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:showIn="navigation_view">
<group android:checkableBehavior="single">
<item android:title="Authentication">
<menu android:checkableBehavior="all">
<item
android:id="#+id/nav_signout"
android:icon="#drawable/ic_menu_gallery"
android:title="Sign out" />
</menu>
</item>
</group>
</menu>
Since you are overriding onNavigationItemSelected I suppose you implemented NavigationView.OnNavigationItemSelectedListener directly to your activity/fragment.
Make sure you added it to your navigation when it is created
navigation_view.setNavigationItemSelectedListener(this)
Or other option would be to implement it directly to your navigation instead of activity/fragment. Remove code you posted and activity/fragment implementation and use kotlin lambdas like this
navigation_view.setNavigationItemSelectedListener{
TODO("Not yet implemented")
val id = item.itemId
if (id == R.id.nav_signout) {
Toast.makeText(this, "Sign out", Toast.LENGTH_SHORT).show()
}
return true
}
In my app i have one activity with two fragment, the app has a toolbar with search action, that search action must be visible only in the second fragment.
So how could i hide the search button and show it only when i'm in fragment2?
My menu.xml looks like this:
<menu 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"
tools:context="it.gabtamagnini.visualstock.MainActivity">
<item
android:id="#+id/action_settings"
android:orderInCategory="100"
android:title="#string/action_settings"
app:showAsAction="never" />
<item
android:id="#+id/app_bar_search"
android:icon="#drawable/ic_search_black_24dp"
android:title="#string/cerca"
app:showAsAction="ifRoom|withText"
app:actionViewClass="android.widget.SearchView" />
</menu>
I'm using kotlin
In your second fragment:
#Override
public void onPrepareOptionsMenu(Menu menu) {
MenuItem item = menu.findItem(R.id.app_bar_search);
if(item != null)
{
item.setVisible(false);
}
}
I solved by adding the following code in my onViewCreated
setHasOptionsMenu(true)
And i had to override the onPrepareOptionsMenu like this:
override fun onPrepareOptionsMenu(menu: Menu) {
super.onPrepareOptionsMenu(menu)
val item: MenuItem = menu.findItem(R.id.app_bar_search)
item.isVisible = true
}
I have created a menu icon on action bar. When it is clicked, I expect it will show something like this
But it display on the left hand side instead.
What could be this issue ?
override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) {
inflater!!.inflate(R.menu.fragment_menu, menu)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
val id = item.getItemId()
if (id == R.id.more) {
var popup: PopupMenu? = PopupMenu(context!!, view!!)
popup?.menuInflater?.inflate(R.menu.pop_up_menu, popup.menu)
popup?.show()
popup?.setOnMenuItemClickListener({ item: MenuItem? ->
when (item!!.itemId) {
R.id.logOut -> {
}
}
true
})
} else
super.onOptionsItemSelected(item)
return true
}
fragment_menu
<?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/more"
android:title="menu"
app:showAsAction="always"
android:icon="#drawable/ic_more"/>
</menu>
pop_up_menu
<?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/logOut"
app:showAsAction="always"
android:title="Log Out"
/>
</menu>
The view I passing is this
#Nullable
public View getView() {
return this.mView;
}
You are passing the wrong view as what #CodeRed mentioned.
Replace
var popup: PopupMenu? = PopupMenu(context!!, view!!)
to
val vItem = getActivity().findViewById<View>(R.id.more)
var popup: PopupMenu? = PopupMenu(context!!, vItem)
Menu in ActionBar is populated automatically by system, you don't need to write code to populate it.
To achieve the menu like figure 1, fragment_menu should be like:
<menu>
<item android:title="Search" />
<item android:title="Locate" />
<item android:title="Refresh" />
<item android:title="Help" />
<item android:title="Check for update" />
</menu>
onOptionItemSelected is used to handle when above menu is clicked, not used to show the menu.
popup menu is free position menu like right click menus in windows, not the one you expect in figure 1.
Okay, so I have a dynamic menu (In my navigation drawer), generated like so:
In my Main.java onCreate():
DatabaseManager databaseAccess = DatabaseManager.getInstance(this);
databaseAccess.open();
List<String> folders = databaseAccess.getFolders();
databaseAccess.close();
// Set up the menu items
setupMenu(folders);
This gets the headings into an array called 'folders', then runs the setupMenu function:
private void setupMenu(List<String> folders) {
// Sets up the menu
Log.i("Folder Size",String.valueOf(folders.size()));
NavigationView navView = findViewById(R.id.nav_view);
Menu menu = navView.getMenu();
int x = 0;
while(x < folders.size()) {
menu.add(R.id.myfolders,Menu.NONE,Menu.NONE,folders.get(x++));
}
navView.invalidate();
}
Which adds it to the id:myfolders in activity_main_drawer:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:showIn="navigation_view">
<item android:title="My Folders"
android:orderInCategory="1"
android:id="#+id/myfolders">
<menu></menu>
</item>
<item android:checkableBehavior="single" android:orderInCategory="2">
<menu android:id="#+id/about_menu">
<item android:id="#+id/system_about"
android:title="About"
android:icon="#drawable/ic_info" />
</menu>
</item>
</menu>
This all works perfectly, however I want to add longpress functionality to my menu items. I have no idea how to go about doing this, can anyone help?
You get a MenuItem from menu.add() then you can call:
menuItem.getActionView().setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
return false; // true
}
});
But not before you set action view: menuItem.setActionView(new ImageButton(this)).
I have a navigation menu which looks like this -
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="#+id/nav_home"
android:icon="#drawable/ic_home"
android:title="Home" />
<item
android:id="#+id/nav_logout"
android:icon="#drawable/ic_logout"
android:title="Logout" />
<item
android:id="#+id/choose_bus"
android:title="Choose a bus">
<menu>
<group
android:id="#+id/group_select_bus"
android:checkableBehavior="single">
<!--<item-->
<!--android:id="#+id/menu_option1"-->
<!--android:title="Bus 1" />-->
<!--<item-->
<!--android:id="#+id/menu_option2"-->
<!--android:title="Bus 2" />-->
</group>
</menu>
</item>
I want to add menu_option1 and menu_option2 dynamically from the activity. I tried this but nothing adding -
#Override
public boolean onNavigationItemSelected(MenuItem item) {
NavigationView navView = (NavigationView) findViewById(R.id.nav_view);
Menu menu = navView.getMenu();
MenuItem item1 = menu.getItem(2);
SubMenu subMenu = item1.getSubMenu();
subMenu.add("Bus 1");
subMenu.add("Bus 2");
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
return true;
}
Try some thing like this
Menu menu = navView.getMenu();
menu.add(R.id.group_select_bus,Menu.NONE,Menu.NONE,Youritem);
Try this:
MenuItem item = mNavigationView.getMenu().getItem(2);
item.getSubMenu().add(R.id.group_select_bus, id, Menu.NONE, "Youritem");
Another approach is to add all items in navigation menu and then change their visibility on specific activity or fragment, like
MenuItem item = mNavigationView.getMenu().getItem(5);
item.setVisible(false);
Seems a little late to answer. There is workaround/hack for this. No need to add list. Just add this little line above your code. It surely works.
override fun onNavigationItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.candidates -> {
binding.navSideView.post {
navSideView.menu.findItem(R.id.candidateManagement).isVisible = !navSideView.menu.findItem(R.id.candidateManagement).isVisible
}
}
}
return true
}
You need to add navigationview.post Runnable before changing visibility. It will update the menu. It works with group too. :)