This is my layout for a menu.
Notice the item:
<?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/action_best_stores"
android:title="#string/showStores"
android:onClick="showHideStores"
android:enabled="true"
android:checkable="true"
app:showAsAction="never"
/>
</menu>
This is the onAction function.
public void showHideStores(MenuItem m) {
m.setChecked(!m.isChecked());
SHOWING_STORES = !SHOWING_STORES;
showStoresProcess(SHOWING_STORES);
refreshData();
invalidateOptionsMenu();
}
Whenever I run my program, the function works because things that are supposed to happen, happen. Except, for the part where the ItemMenu itself changes... It just doesn't do anything, the checkbox stays unchecked... I also tried setTitle, doesn't change anything either.
So, line 1 isn't producing any change.
What is going on?
This is the code where I inflate the Menu
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main_list_actions, menu);
super.onCreateOptionsMenu(menu);
this.menu = menu;
refreshData();
return true;
}
Notice how the function works because the screen changes, but the menu itself doesn't get "checked off" or "unchecked".
The problem is explained as follow:
When you call invalidateOptionsMenu(), it will reset to default menu. So nothing happened.
Solution: override onPrepareOptionsMenu()
#override
public bool onPrepareOptionsMenu(Menu menu)
{
super.onPrepareOptionsMenu(menu);
MenuItem m = memenu.findItem(R.id.YourItemId);
m.setChecked(!m.isChecked());//something like this
return true;
}
Remove your call to invalidateOptionsMenu(). Calling invalidateOptionsMenu() is going trigger a call back to onCreateOptionsMenu() which is going to create a new menu which will create a new un-checked MenuItem, basically exactly what you don't want to halpen.
Related
I have been reading answers to questions on here for hours and no solutions seem to work for me.
I am creating an android app for DnD Character Creations, and if the user selects a magical class, I would like to add a spell book option to the main menu.
For some reason, no matter what I do, it will either show visible or invisible based on the XML and will not change it through the code.
This is my XML:
<?xml version="1.0" encoding="utf-8"?>
<!--TODO: create related icons-->
<group android:checkableBehavior="single">
<item
android:id="#+id/nav_profile"
android:title="Profile"
android:visible="true"/>
<item
android:id="#+id/nav_battle"
android:title="Battle"
android:visible="true"/>
<item
android:id="#+id/nav_items"
android:title="Items"
android:visible="true"/>
<item
android:id="#+id/nav_spellbook"
android:title="Spell Book"
android:visible="false"/>
</group>
This was attempt 1 in java:
public void classBasedTraits() {
int intHealthInitial = 0;
//end attempt
switch (strCharacterClass) {
case "Sorcerer":
case "Wizard":
intHealthInitial = 6; // Sorcerer and Wizard's initial health is 6
break;
case "Bard":
case "Cleric":
case "Druid":
case "Monk":
case "Rogue":
case "Warlock":
intHealthInitial = 8; // Bard, Cleric, Druid, Monk, Rogue, and Warlock's initial health is 8
break;
case "Fighter":
case "Paladin":
case "Ranger":
intHealthInitial = 10; // Fighter, Paladin, and Ranger's initial health is 10
break;
case "Barbarian":
intHealthInitial = 12; // Barbarian's initial health is 12
break;
}
//Attempt to create spellbook for magical classes'
Set<String> setMagical;
setMagical = new HashSet<String>(Arrays.asList("Bard", "Cleric", "Druid", "Paladin",
"Ranger", "Sorcerer", "Warlock", "Wizard"));
if(setMagical.contains(strCharacterClass)){
magical = true;
invalidateOptionsMenu();
}
intTotalHP = intHealthInitial + intConstitutionMod; // Starting HP is initial health + constitution modifier
intRemainingHP = intTotalHP; // Sets character at full health
}
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.activity_main_drawer, menu);
menu.findItem(R.id.nav_spellbook).setVisible(magical);
return super.onPrepareOptionsMenu(menu);
}
this was attempt 2 in java, in the Profile activity class, because this class is called after the character class has been specified, and this function is when the menu is set up for the first time:
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.activity_main_drawer, menu);
Set<String> setMagical;
setMagical = new HashSet<String>(Arrays.asList("Bard", "Cleric", "Druid", "Paladin",
"Ranger", "Sorcerer", "Warlock", "Wizard"));
MenuItem spellbook = menu.findItem(R.id.nav_spellbook);
if(setMagical.contains(characterClass))
{
spellbook.setVisible(true);
}
else
{
spellbook.setVisible(false);
}
return true;
}
Here is the project on github if anyone want's to take a look at the full code
https://github.com/Doszust/RPG-Character-Sheet/tree/master/app/src/main/java/com/ucfknights/dylan_oszust/dungeonsanddragons
You were on the right track with the first attempt. You use invalidateOptionsMenu() to trigger a call to onPrepareOptionsMenu() where you implement your changes to the menu.
You need to return true from onPrepareOptionsMenu() in order for it to be displayed.
Also don't inflate the menu again in onPrepareOptionsMenu(). You are already supplied the menu in the method parameters.
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.activity_main_drawer, menu);
return true;
}
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
menu.findItem(R.id.nav_spellbook).setVisible(magical);
return true;
}
Your menu file should 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/nav_profile"
android:title="Profile"
android:visible="true"/>
<item
android:id="#+id/nav_battle"
android:title="Battle"
android:visible="true"/>
<item
android:id="#+id/nav_items"
android:title="Items"
android:visible="true"/>
<item
android:id="#+id/nav_spellbook"
android:title="Spell Book"
android:visible="false"/>
</group>
</menu>
So onCreateOptionsMenu() is where you first create the menu. Then onPrepareOptionsMenu() is where you can modifiy it from then on.
For anyone who is also looking to fix this problem with the nav_drawer menu, you have to access it differently than the standard options menu (Thanks to Sound Conception for pointing out the difference). The code should get the menu from the navigation view.
The working code is below, it is the initial menu builder for the app, and it checks to see if the class is a magical class before deciding to show or hide the spellbook option in the nav drawer.
#Override
public boolean onCreateOptionsMenu(Menu menu) {
Set<String> setMagical;
setMagical = new HashSet<String>(Arrays.asList("Bard", "Cleric", "Druid", "Paladin",
"Ranger", "Sorcerer", "Warlock", "Wizard"));
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
Menu nav_Menu = navigationView.getMenu();
MenuItem spellbook = nav_Menu.findItem(R.id.nav_spellbook);
if(setMagical.contains(characterClass))
{
spellbook.setVisible(true);
}
else
{
spellbook.setVisible(false);
}
return true;
}
Graying out the Save item in toolbar only happens in design mode but never on runtime.
I'm using this code:
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
if(count > 0) {
menuItemSave.setEnabled(true);
} else {
menuItemSave.setEnabled(false);
}
return true;
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.options_menu, menu);
menuItemSave = menu.findItem(R.id.save);
return true;
}
It's enabling/disabling but it just really not turning into gray when disabled.
You can use custom color to change color when button is enabled or disabled. [ Change color according to your requirement ]
colors/custom_button_color.xml:
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="#FF0000" android:state_enabled="false" />
<item android:color="#CCCCCC"/>
</selector>
In menu.xml file set to your required button item like
android:textColor="#color/custom_button_color"
According to Android docs onPrepareOptionsMenu is called just before menu is opened.But if menu is always open, it will not be called.
So,
On Android 3.0 and higher, you must call invalidateOptionsMenu() when you want to update the menu that is always open. The system will then call onPrepareOptionsMenu() so you can update the menu items.
I have a refresh icon on my menu which when clicked will refresh the contents of the Activity. But the problem is that the refresh icon is still clickable while it is refreshing which I do not want. Here is my menu.xml file
<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=".MainActivity">
<item
android:id="#+id/action_refresh"
android:orderInCategory="100"
android:icon="#mipmap/ic_refresh"
android:enabled="true"
android:title="#string/action_settings"
app:showAsAction="always"/>
And here is where I handle the click event for the icon
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_refresh) {
// getData() fetches the data and updates the display
getData();
return true;
}
return super.onOptionsItemSelected(item);
}
Also, is there a way to maybe dim the icon so that the user knows that they have already clicked the icon?
When you click the icon, use the isEnabled() method of your Menuitem to check if it is currently enabled. If it is, then disable it until the data is loaded. Once the data loads successfully, then you can enable it again. Example:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if(item.isEnabled()) {
// "Dim" the icon like you said. You can use other alpha values if you like.
item.getIcon().setAlpha(130);
// Disable the menu icon
item.setEnabled(false);
}
getData();
return true;
}
return super.onOptionsItemSelected(item);
}
Now, you said that you have a getData() method which updates the display after it fetches the data. Once the data is fetched, check if the Menuitem is disabled. If it is disabled, then enable it again. Example:
if(item != null && item.isEnabled() == false) {
// "Undim" the icon
item.getIcon().setAlpha(255);
// Enable it again
item.setEnabled(true);
}
You can use setEnabled(true) method to enable/disable menu item
You could create a second menu.xml, that is used after the refresh button is clicked. To force a menu redraw call invalidateOptionsMenu();
In this second menu.xml, the refresh button could be disabled, or switched to a diffrent one, indicating the user, that the refresh is on going.
Easiest way to fix this is to hold on to the menu item in your activity.
private MenuItem mRefreshItem;
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater infl = new MenuInflater(this);
infl.inflate(R.menu.menu, menu);
mRefreshItem = menu.findItem(R.id.action_refresh);
return super.onCreateOptionsMenu(menu);
}
/** Call this when you begin or end loading */
private void setRefreshEnabled(boolean enabled) {
mRefreshItem.setEnabled(enabled);
}
For the first time i use the contextual actionbar. When i click in the item of my ListView i want have the possibility to share that item in some way (whatsapp/mail/gmail/drive etc etc..). I'm trying in with this method but no works:
the menu layout:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="#+id/shareButton"
android:actionProviderClass="android.widget.ShareActionProvider"
android:title="#string/share"
android:showAsAction="always"/>
</menu>
The contextual actionbar class:
public class CABMode implements ActionMode.Callback {
private ShareActionProvider mshare;
#Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
mode.getMenuInflater().inflate(R.menu.cab, menu);
return true;
}
#Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
// don't need to do anything
return false;
}
#Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
mshare = (ShareActionProvider) item.getActionProvider();
mshare.setShareIntent(Share());
return true;
}
#Override
public void onDestroyActionMode(ActionMode mode) {
Mode = null;
}
public Intent Share() {
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType("text/plain");
intent.putExtra(Intent.EXTRA_TEXT, "Share");
return intent;
}
}
Well, the contextual actionbar it opens well when i do an long click, but the share button in the actionbar doesn't work. When i say "not works" i mean that seems not clickable. Nothing works when i click over the item. Nothing appears. What i want it's open the multiple share ways. Thanks
When i say "not works" i mean that seems not clickable
ActivityChooserView, the action view ShareActionProvider returns, disables the "share" button when there are no items to display, which in your case if because you're setting up ShareActionProvider incorrectly. All of the "on click" events are handled internally, you won't receive any callbacks to ActionMode.Callback.onActionItemClicked.
Rather than settings it up in ActionMode.Callback.onActionItemClicked, move that code into ActionMode.Callback.onCreateActionMode and call Menu.findItem to initialize it.
#Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
mode.getMenuInflater().inflate(R.menu.cab, menu);
final MenuItem item = menu.findItem(R.id.your_share_action_provider_id);
mshare = (ShareActionProvider) item.getActionProvider();
mshare.setShareIntent(Share());
return true;
}
When I touch this "Edit" button I want it to change to "Done". Is there a way to do this?
I tried this but it only works when opening the menu on the right side:
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
// change the text here.
return super.onPrepareOptionsMenu(menu);
}
I assume that, at some point, you inflate the menu, yes?
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.some_menu_layout, menu);
return true;
}
So you can go into your menu (in this case, res/menu/some_menu_layout.xml), and find the android:id of the menu item you want to find. You should then be able to use menu.findItem(theId).setTitle("Done");. (You may have to save your Menu variable as a local member to do this.)