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;
}
Related
I'm building an app which has menu item in toolbar, i have created submenu for one menu i.e whose id is 'cloud'. I would like to implement onclick on each submenu when click will open different activity.
Here is the menu.xml file
<?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_refresh"
app:showAsAction="ifRoom"
android:title="Refresh"
android:icon="#drawable/ic_loop_black_24dp"></item>
<item
android:id="#+id/notes"
app:showAsAction="ifRoom"
android:title="Refresh"
android:icon="#drawable/ic_event_note_black_24dp"></item>
<item
android:id="#+id/cloud"
app:showAsAction="ifRoom"
android:title="Refresh"
android:icon="#drawable/ic_cloud_upload_blackt_24dp">
<menu>
<group
android:checkableBehavior="single">
<item android:id="#+id/imageee"
android:title="Image Upload"
android:orderInCategory="100"
app:showAsAction="ifRoom" />
<item android:id="#+id/pdfff"
android:title="Pdf Upload"
android:orderInCategory="100"
app:showAsAction="never"/>
</group>
</menu>
</item>
</menu>
Here is the Mainactivity file
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
mymenu = menu;
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch(item.getItemId()) {
case R.id.action_refresh:
Intent intent = new Intent(MainActivity.this, UpdateService.class);
startService(intent);
}
return true;
case R.id.notes:{
Intent activity_weather = new Intent(this,Physics.class);
startActivity(activity_weather);
}
return true;
case R.id.cloud:{
}
return true;
}
return super.onOptionsItemSelected(item);
}
I looked for answer and tried on my own but I have no idea how to achieve this.
Any help is appreciated.
Thank you in advance.
I have a solution for you:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_refresh:
// TODO:
toast("refresh");
return true;
case R.id.notes:
// TODO:
toast("notes");
return true;
case R.id.imageee:
// TODO: Start your image upload
toast("imageee");
return true;
case R.id.pdfff:
// TODO: Start your PDF upload
toast("pdfff");
return true;
default:
return super.onOptionsItemSelected(item);
}
}
public void toast(String message) {
Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
}
I write toast method to show a toast when users click on an item on menu or sub menu. Please remove //TODO: line and add your code for each case there.
I don't think you want to have
android:checkableBehavior="single"
set on your submenu. This behaviour is only useful if you just want to capture the choice (or choices) in the menu item, but not if you actually want to react (ie: do something) when the user selects a submenu item.
Based on your question, it sounds like you want to launch another Activity when the user selects one of these submenu items. To do that just add those menu items to the switch statement in onOptionsItemSelected():
case R.id.imageee:
Intent imageIntent = new Intent(this, Upload.class);
startActivity(imageIntent);
return true;
case R.id.pdfff:
Intent pdfIntent = new Intent(this, Pdf.class);
startActivity(pdfIntent);
return true;
Another interesting solution could be:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
Intent intent = new Intent();
switch (item.getItemId()) {
case R.id.action_refresh:
intent.setClass(this, UpdateService.class);
break;
case R.id.notes:
intent.setClass(this, Physics.class);
break;
case R.id.cloud:
intent = null;
break
case R.id.imageee:
// TODO set intent class
break;
case R.id.pdfff:
// TODO set intent class
break;
}
// If the selected item is the one that opens the submenu does not try to start the
// activity avoiding throwing null pointer exception and consequently opens the submenu
if (!(intent == null))
startActivity(intent);
return super.onOptionsItemSelected(item);
}
That way you avoid having to have multiple times, in all cases the same call to the method.
startActivity()
Saving lines of code. It is even more advantageous if you decide to add more items to the menu.
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.
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.
On my ActionBar there is one item that has an icon about a star(without filled).
When the user clicks on it, the icon changes to another icon(filled star).
But the problem is that if the user cliccks again the icon doesn't change one more time.
So, this is what i want
icon1->click->icon2->click->icon1->click->icon2
My item xml:
<item
android:id="#+id/bookmark"
android:icon="#drawable/bookmark"
android:showAsAction="ifRoom"
android:title="Add to Favorites"/>
My Java for actionBar:
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
menu.clear();
inflater.inflate(R.menu.activity_desc, menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if(item.getItemId() == R.id.bookmark){
// i tried this: something like: if(item.getIcon() == (R.drawable.nobookmark){} it doesn't work
item.setIcon(R.drawable.nobookmark);
return true;
}
return true;
}
In your item.xml make it checkable:
<item
android:id="#+id/bookmark"
android:icon="#drawable/nobookmark"
android:checkable="true"
android:showAsAction="ifRoom"
android:title="Add to Favorites"/>
In the java you must manually toggle the checked state and select the icon:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if(item.getItemId() == R.id.bookmark){
item.setChecked(!item.isChecked());
item.setIcon(item.isChecked() ? R.drawable.bookmark : R.drawable.nobookmark);
return true;
}
return false;
}
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;
}