How to create a submenu with radio buttons in Android? - android

I have a problem in a simple case (at least, it looks like so). I need to create a submenu for a context menu dynamically and provide each item with a radiobox. I made a lot of trials. When I call menu.setGroupCheckable(0, true, true), where 0 is by default the menu itself, it displays radio buttons to the right on every menu item as expected, but I need this for submenu. So I have the following code:
SubMenu sub = menu.addSubMenu(R.string.name);
int count = 1000;
for(String e : someList)
{
MenuItem item = sub.add(1, count, count, e);
count++;
}
menu.setGroupCheckable(1, true, true);
In this case I don't see neither radioboxes, nor checkboxes in the submenu. Then I wrote the following code:
SubMenu sub = menu.addSubMenu(R.string.name);
int count = 1000;
for(String e : someList)
{
MenuItem item = sub.add(1, count, count, e);
item.setCheckable(true);
count++;
}
menu.setGroupCheckable(1, true, true);
This makes the submenu to have a checkbox in every item, and the checkboxes work exclusively, but I want radioboxes, because they look more intuitively for exclusive selection.
So, how can this be accomplished?

Set the checkableBehavior in xml to single.
Here is some code:
<menu>
<group android:id="#+id/group"
android:checkableBehavior="single">
<item android:id="#+id/menu_sort_by_name"
android:title="#string/action_sort_by_name"/>
<item android:id="#+id/menu_sort_by_last_edit"
android:title="#string/action_sort_by_last_edit"/>
</group>
</menu>

I found out that groups of menus and submenus are processed separately, that is a group formed in a submenu, should be addressed via the submenu, not via the top-level menu. So the solution is to call:
sub.setGroupCheckable(1, true, true);
This code works as expected, that is items in the submenu show radiobuttons instead of checkboxes.

Related

how to make navigation drawer menu items center in android

First of all I saw one stack thread regarding the same question but its not completely working for me may be because I am a newbie if anybody knows please help me , I am in navigation drawer now I want make the menu items to align in center something just like this
this is what I got from stack overflow
int positionOfMenuItem = 0; //or any other postion
MenuItem item = menu.getItem(positionOfMenuItem);
SpannableString s = new SpannableString(settingsItemTitle);
s.setSpan(new AlignmentSpan.Standard(Alignment.ALIGN_CENTER), 0, s.length(), 0);
item.setTitle(s);
I wrote this code in activity main and I am not sure that what is settingsItemTitlein this code so studio giving me error
Cannot resolve symbol 'settingsItemTitle'
if anybody knows please help me
Instead of using MenuItem (along with, I'm guessing, NavigationView), just use a vertical LinearLayout for your drawer content. You'll be able to style it any way you want.
You can try developing a custom drawer where you can place the menu items in the centre.
Custom navigation drawer
settingsItemTitle should be replaced by the title of your MenuItem.
In case the title was already set in the menu layout file, you could rewrite your code like:
int positionOfMenuItem = 0; //or any other postion
MenuItem item = menu.getItem(positionOfMenuItem);
SpannableString s = new SpannableString(item.getTitle());
s.setSpan(new AlignmentSpan.Standard(Alignment.ALIGN_CENTER), 0, s.length(), 0);
item.setTitle(s);
This works, if you call it in the overwritten onCreateOptionsMenu method of your Activity, after having inflated the menu.
If you intend to do it for all items of your menu, you need to loop over them. Something like:
for(int i = 0; i < menu.size(); i++) {
MenuItem item = menu.getItem(i);
SpannableString s = new SpannableString(item.getTitle());
s.setSpan(new AlignmentSpan.Standard(Alignment.ALIGN_CENTER), 0, s.length(), 0);
item.setTitle(s);
}
I think setting this in an own layout, as Gavin pointed out in his answer, would be neater, but come at the price of not being able to use the Android off the shelf menu.

Change background color of the selected button basing on its state

I saw some posts with a similar question but they still differ from my problem here. I am making painting app in Android Studio and I want to indicate the option which user selected (whether it is move tool, pencil etc.) Here is the picture:
So, I want to change the background color of the button when it is selected and revert it back to default color when another button is selected.
I tried doing it with XML selector but later I saw that there is now "selected" attribute for a regular button. These are regular buttons. What is the easiest way to solve this?
Try this code (button_selector.xml, put it in your drawable folder)
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#android:color/holo_blue_dark" android:state_selected="true"></item>
<item android:drawable="#android:color/holo_blue_dark" android:state_pressed="true"></item>
<item android:drawable="#android:color/darker_gray"></item>
</selector>
XML
<Button
android:background="#drawable/button_selector" />
You could use a class variable for keeping track of the currently selected button, and detect when a new button is selected. You would then perform the action of "selecting" the new button, and "deselecting" the previous one. Example:
private Button mSelectedButton;
private void setOnClickListeners() {
View.OnClickListener listener = new View.OnClickListener() {
#Override
public void onClick(View view) {
Button clickedButton = (Button) view;
//in case no button is selected, this will only "select" the clickedButton
if (mSelectedButton == null) mSelectedButton = clickedButton;
//previous selected button (should return to original state)
mSelectedButton.setBackgroundColor(R.color.original_state);
//your new selected button
clickedButton.setBackgroundColor(R.color.selected_state);
mSelectedButton = clickedButton; //save currently selected button
}
};
yourButton1.setOnClickListener(listener);
yourButton2.setOnClickListener(listener);
yourButton3.setOnClickListener(listener);
...
}

Set no item pre-selected in Bottom Navigation view

I'm adding the new Bottom Navigation View from the material design library to a project, and I would like to have no pre selected item by default.
For now first item is selected by default.
I have used
mBottomNavigation.getMenu().getItem(0).setChecked(false);
but when doing it in for loop for all the menu item last item is selected again by default.
Is there a way we can achieve this?
Not sure about the proper way to achieve this but a work around will help-
setCheckable(false) for first item
navigation.getMenu().getItem(0).setCheckable(false);
item.setCheckable(true) inside onNavigationItemSelected()
public boolean onNavigationItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.navigation_home:
item.setCheckable(true);
mTextMessage.setText(R.string.title_home);
return true;
}
return false;
}
I came up with another solution
Just add one more item to your menu.xml file for example
This is my bottom_nav_menu.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="#+id/navigation_home"
android:icon="#drawable/ic_home_black_24dp"
android:title="#string/home" />
<item
android:id="#+id/navigation_cart"
android:icon="#drawable/ic_shopping_cart_black_24dp"
android:title="#string/cart" />
<item
android:id="#+id/navigation_wishlist"
android:icon="#drawable/ic_favorite_border_black_24dp"
android:title="#string/wish_list" />
<item
android:id="#+id/navigation_account"
android:icon="#drawable/ic_person_black_24dp"
android:title="#string/account" />
<!-- Our invisible item -->
<item
android:id="#+id/invisible"
android:visible="false"
android:icon="#drawable/ic_person_black_24dp"
android:title="#string/account" />
</menu>
Notice that I have added that item at last position and given it an id invisible and also set it's visibility to false.
Now, In the activity just set selected item id to this id like this
bottomNavMenu.setSelectedItemId(R.id.invisible);
Thanks
XML Code
<group android:checkableBehavior="single">
<item android:id="#+id/nav_item1" />
<item android:id="#+id/nav_item2" />
<item android:id="#+id/nav_item3" />
<item android:id="#+id/nav_item4" />
<item
android:id="#+id/nav_item5"
android:icon="#drawable/icon_item5"
android:title="Home"
android:visible="false"/>
</group>
JAVA Code
bottomNavigationView.getMenu().getItem(4).setChecked(true);
bottomNavigationView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem menuItem) {
switch (menuItem.getItemId()) {
case R.id.nav_item1:
return true;
case R.id.nav_item2:
return true;
case R.id.nav_item3:
return true;
case R.id.nav_item4:
return true;
}
// Default operation you want to perform
return false;
}
});
If anyone interested in a nice Kotlin solution, here's mine:
//disable the preselected first item
//<navigation> is the bottom navigation view
navigation.menu.getItem(0).isCheckable=false
Then in the selection listener, make sure that you'll show the user what he selected
BottomNavigationView.OnNavigationItemSelectedListener { item: MenuItem ->
when (item.itemId) {
R.id.option1 -> {
item.isCheckable=true //here is the magic
//notify the listener
return#OnNavigationItemSelectedListener true
}
R.id.option2 ->{
item.isCheckable=true
//notify the listener
return#OnNavigationItemSelectedListener true
}
R.id.option3 ->{
//go to forgot user fragment
item.isCheckable=true
//notify the listener
return#OnNavigationItemSelectedListener true
}
else -> false
}
}
Finally , make a selector color so you can change easily in color
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="true"
android:color="#color/colorAccent" />
<item android:color="#color/colorPrimary" />
And add the selector to the navigation view
app:itemIconTint="#color/navigation_colors"
app:itemTextColor="#color/navigation_colors"
Now, if you need to change the colours, just change the selector.
Add this line in your onCreate method
mBottomNavigation.setSelectedItemId("ID OF YOUR MENU ITEM");
Use setCheckable instead of setChecked(false) in line:
mBottomNavigation.getMenu().getItem(0).setCheckable(false);
It works for me.
I've created a sample project and by default there is no checked item. Just make sure you don't have any navigationView.setCheckedItem(R.id.id) on your code.
My solution was to select a different tab and immediately after select the tab I initially wanted.
bottomNavigationView.selectedItemId = R.id.dummy_tab
bottomNavigationView.selectedItemId = R.id.tab_to_select
The setOnItemReselectedListener disables reselect tab selections, but the navigationView has a default tab selected and don't render after creation because is invoking setOnItemReselectedListener
Tried the invisible solution but didn't work with programmatically bottomMenu creation.
Old question, but if you still facing issue - just use this:
bottomNavigationView.getMenu().getItem(0).setCheckable(false);
And it:
bottomNavigationView.setOnItemReselectedListener(new NavigationBarView.OnItemReselectedListener() {
#Override
public void onNavigationItemReselected(#NonNull MenuItem item) {
if (item.getItemId() == R.id.navigation_home) {
item.setCheckable(true);
}
}
});
I combined the solution mentioned by #Ashish Kumar and resolved my query and
private void customizeBottomBar() {
mBottomNavigation.getMenu().getItem(0)
.setIcon(ContextCompat.getDrawable(activity, R.drawable.ic_reserve_normal));
changeMenuItemCheckedStateColor(mBottomNavigation, getUnCheckedColor(), getUnCheckedColor());
}
/**
* Method to change the color state of bottom bar view
* #param bottomNavigationView - BottomNavigation view instance
* #param checkedColorHex int value of checked color code
* #param uncheckedColorHex int value of unchecked color code
*/
void changeMenuItemCheckedStateColor(BottomNavigationView bottomNavigationView,
int checkedColorHex, int uncheckedColorHex) {
int[][] states = new int[][]{
new int[]{-android.R.attr.state_checked}, // unchecked
new int[]{android.R.attr.state_checked}, // checked
};
int[] colors = new int[]{
uncheckedColorHex,
checkedColorHex
};
ColorStateList colorStateList = new ColorStateList(states, colors);
bottomNavigationView.setItemTextColor(colorStateList);
bottomNavigationView.setItemIconTintList(colorStateList);
}

How to uncheck checked items in Navigation View?

I know it's possible to highlight a navigation view item by calling setCheckedItem() or return true value in onNavigationItemSelected to display the item as the selected item, but How can I uncheck the checked items of a navigation view?
This will uncheck the items:
int size = mNavigationView.getMenu().size();
for (int i = 0; i < size; i++) {
mNavigationView.getMenu().getItem(i).setCheckable(false);
}
I saw #arsent solution and gave it a try, and it will indeed do what you want, which is to unselect all the items... but, I was having an issue in the following scenario:
Select menu item 1 (using NavigationView#setCheckedItem)
Unselect all the items as per #arsent's solution
Select menu item 1 again (using NavigationView#setCheckedItem)
In this scenario, item 1 will not be marked as checked. That's because internally the navigation view keeps track of the previously selected item set in step 1, which doesn't change in step 2, and it just skips step 3 because the previously selected item is the same as the one we're selecting now.
My suggestion (and an alternative solution) to avoid this is just having a dummy invisible item and use NavigationView#setCheckedItem to select that item whenever you want to unselect all, like so
<item
android:id="#+id/menu_none"
android:title=""
android:visible="false"/>
To unselect all just do
mNavigationView.setCheckedItem(R.id.menu_none);
To uncheck all MenuItems including SubMenu items you have to use recursion -
private void unCheckAllMenuItems(#NonNull final Menu menu) {
int size = menu.size();
for (int i = 0; i < size; i++) {
final MenuItem item = menu.getItem(i);
if(item.hasSubMenu()) {
// Un check sub menu items
unCheckAllMenuItems(item.getSubMenu());
} else {
item.setChecked(false);
}
}
}
Call above method for unchecking all items, like below -
unCheckAllMenuItems(navigationView.getMenu());
just make your items non checkable like so
<item
android:id="#+id/profile_item"
android:checkable="false"
android:title="#string/profile"/>
Quoting #Codeversed, there is "no need to loop menu items with added overhead!". But, there is no need to create multiple groups (in this case he is creating the #+id/grp1 and #+id/grp2) to uncheck a previous checked item.
You can simple add a single group for all elements with the android:checkableBehavior, like this:
<group android:checkableBehavior="single">
<item
android:id="#+id/id1"
android:checked="true"
android:icon="#drawable/drawable1"
android:title="#string/string1" />
<item
android:id="#+id/id2"
android:icon="#drawable/drawable2"
android:title="#string/string2" />
</group>
Joao's solutions didn't not work for me as totally expected. This would lead to a blank space from unchecked Item View on my Navigation.
Just make sure to set the view as gone:
<item
android:id="#+id/your_menu_item_id_to_hide"
android:title=""
android:visible="false"/>
bottomNavigationView.getMenu().findItem(R.id.your_menu_item_id_to_hide).setChecked(true);
bottomNavigationView.findViewById(R.id.your_menu_item_id_to_hide).setVisibility(View.GONE);
Arsent solution is not necessary in this case.
All you need to do is surround your groups like this:
<group>
<group
android:id="#+id/grp1">
<item
android:id="#+id/nav_profile"
android:icon="#drawable/ic_account_circle_24dp"
android:title="#string/profile" />
</group>
<group
android:id="#+id/grp2">
<item
android:id="#+id/nav_settings"
android:icon="#drawable/ic_settings_24dp"
android:title="#string/settings" />
<item
android:id="#+id/nav_help"
android:icon="#drawable/topic_help"
android:title="#string/help_feedback" />
</group>
</group>
No need to loop menu items with added overhead!
I guess someone like me use those methods just like this
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.nav_today:
break;
case R.id.nav_calendar:
navigationView.getMenu().performIdentifierAction(R.id.nav_today, 0);
navigationView.getMenu().getItem(0).setChecked(true);//or
navigationView.setCheckedItem(R.id.nav_today);//or
drawerLayout.closeDrawers();
break;
}
return true;
}
Trying to check R.id.nav_today after you clicked on R.id.nav_calendar, (btw: checkableBehavior="single"), unfortunately it will not work.
That is because after your code navigationView.setCheckedItem(R.id.nav_today) be called then the R.id.nav_today will be checked immediately, but after this, your click on R.id.nav_calendar will check itself.
That is why whatever methods you use seem never work at all. It is work, but be override immediately.
To uncheck it inside NavigationItemSelectedListener I had to use post (to UI thread):
App.getHandler().post(() -> menuItem.setChecked(false));
Full example:
NavigationView navigationView = findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(
menuItem -> {
menuItem.setChecked(true);
mDrawerLayout.closeDrawers();
switch (menuItem.getItemId()) {
...
}
App.getHandler().post(() -> menuItem.setChecked(false));
return true;
});
p.s. in my case App.getHandler() returns Handler instance for UI Thread Lopper
I had to use a combination of all the solutions mentioned here. In my case, I want to open an URL Intent when the Item is clicked (open a Browser). The clicked item should get unchecked after the click and reset to the item before. Important is to understand, that you cannot uncheck an item during the click listener event, since the checked state will be handled afterwards. So this is my solution in Kotlin:
val item = navigationView.menu.findItem(R.id.menu_item)
item.setOnMenuItemClickListener {
val oldItem = navigationView.checkedItem
rootView.postDelayed({ // you can use here any View to post a Runnable with a delay
navigationView.setCheckedItem(oldItem?.itemId ?: R.id.default_item)
}, 500)
browseURL("https://www.example.com")
true
}
I use a Navigation Drawer in combination with the Jetpack Navigation.
i combine #arsent and #Rahul answers and write this code:
private void NavigationView_NavigationItemSelected(object sender, NavigationView.NavigationItemSelectedEventArgs e)
{
var size = navigationView.Menu.Size();
for (int i = 0; i < size; i++)
{
var item= navigationView.Menu.GetItem(i).SetChecked(false);
if (item.HasSubMenu)
{
for (int j = 0; j < item.SubMenu.Size(); j++)
{
item.SubMenu.GetItem(j).SetChecked(false);
}
}
}
e.MenuItem.SetChecked(true);
drawerLayout.CloseDrawers();
}
above code is for xamarin c# and work,but u can easily convert to java
#arsent's answer is correct but setCheckable(false) uncheck all items, it prevents the items from being checked in the future.
Just use setChecked(false)
int size = mNavigationView.getMenu().size();
for (int i = 0; i < size; i++) {
mNavigationView.getMenu().getItem(i).setChecked(false);
}

Use a ColorStateList with a checkable option menu item and state_checked

My options menu is populated with items such as:
<item
android:id="#+id/menu_bus"
android:checkable="true"
android:checked="true"
android:icon="#drawable/icon_bus"
android:title="#string/bus"
app:showAsAction="ifRoom"/>
Here's my onOptionsItemsSelected:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
item.setChecked(!item.isChecked());
Log.d("test", "Item " + item + " is now checked: " + item.isChecked());
ColorStateList colorStateList = getResources().getColorStateList(R.color.options_menu_colors);
Drawable d = DrawableCompat.wrap(item.getIcon());
DrawableCompat.setTintList(d, colorStateList);
item.setIcon(d);
return true;
}
As you can see my goal is to have widget tinting in older versions of android, using the feature of the support libraries v22.1.
The color is defined as such:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="#color/accent" android:state_checked="true"/>
<item android:color="#color/secondary_text"/>
</selector>
However the state_checked isn't working with checkbox menu items!
Here's the log of icon presses:
D/test (11529): Item Bus is checked: false
D/test (11529): Item Bus is checked: true
D/test (11529): Item Bus is checked: false
D/test (11529): Item Bus is checked: true
I tried to switch the selector to state_pressed: this one works! While touching the menu item, the color changes!
So why can't the ColorStateList work with the state_checked on option menu items?
PS: using this works:
int colorId = item.isChecked() ? R.color.accent : R.color.secondary_text;
int color = getResources().getColor(colorId);
DrawableCompat.setTint(d, color);
But obviously I would've wanted something more elegant.
According to the documentation Using checkable menu items,
you have to manually indicate the checked state, for e.g.
if(item.isCheckable()) {
int[] state = {item.isChecked() ? android.R.attr.state_checked : android.R.attr.state_empty};
item.getIcon().setState(state);
}
It likely doesn't work because your Drawable doesn't implement the Checkable interface - the MenuItem is what's checked.

Categories

Resources