Create an Actionbar OptionsMenu in an PreferenceFragment - java

I run into a problem while I was settings up the Preferences for my App.
I would like to have a Button in the ActionBar (e.g. Save) but my ActionBar is not showing anything. I put this Line in the onCreate Method:
this.setHasOptionsMenu(true);
And implemented the
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater)
public boolean onOptionsItemSelected(MenuItem item)
methods as well. However, it does not show anything.

Be sure your button item in your action menu layout something like:
<item
android:id="#+id/action_save"
android:orderInCategory="1"
your_icon:showAsAction="always"
android:icon="#drawable/icon_save"
/>

Related

Update ActionBar menu depending on navigation destination

I would like to change the menu items displayed in my ActionBar depending on the current destination of my NavController. By "change" I mean inflate a specified menu-xml for each destination.
The behavior could be compared to the integrated way the new navigation system changes the ActionBar title, depending on the given android:label for the destination fragment in the navigation-xml.
So far I setup a basic activity with ActionBar and DrawerLayout using the new Android navigation. Also I created all necessary XML files and Fragments to navigate between.
...
#Override
protected void onCreate(Bundle savedInstanceState)
{
...
this._drawerLayout = this.findViewById(R.id.drawer_layout);
Toolbar toolbar = this.findViewById(R.id.action_bar);
this.setSupportActionBar(toolbar);
ActionBar actionbar = Objects.requireNonNull( this.getSupportActionBar() );
actionbar.setDisplayHomeAsUpEnabled(true);
actionbar.setHomeAsUpIndicator(R.drawable.ic_menu);
NavigationView navigationView = this.findViewById(R.id.navigation_view);
navigationView.setNavigationItemSelectedListener(menuItem -> {
menuItem.setChecked(true);
this._drawerLayout.closeDrawers();
return true;
});
NavController navController = Navigation.findNavController(this, R.id.navigation_host);
NavigationUI.setupWithNavController(toolbar, navController, this._drawerLayout);
}
#Override
public boolean onCreateOptionsMenu(Menu menu)
{
// Here I inflate the ActionBar menu that is kept between all destinations.
// Instead of keeping the same menu between all destinations I want to display different menus depending on the destination fragment.
this.getMenuInflater().inflate(R.menu.actionbar_items, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item)
{
switch(item.getItemId())
{
case android.R.id.home:
this._drawerLayout.openDrawer(GravityCompat.START);
return true;
case R.id.appbar_search:
return true;
}
return super.onOptionsItemSelected(item);
}
I thought about using an individual toolbar in each destination fragment
but I discarded the idea, because I would lose the transition animation between hamburger icon and back-arrow icon.
Is there any way to achieve this with the new navigation system or in any other way?
I just tested this. With the current version (2.2.2) of the navigation library, menu items inflated by each fragment will be added and removed as you navigate around.
But onCreateOptionsMenu is not called by default! To make things work, you have to sprinkle the magic dust and call setHasOptionsMenu(true) during initialisation.
Beware, any menu items inflated by the containing activity will always appear alongside the ones from the current fragment, so if you don't want any common menu items, it's probably easiest to not inflate a menu in the Activity.
Side note: in the Fragment class, onCreateOptionsMenu(menu, inflater) is an empty method, so the call to super.onCreateOptionsMenu(menu, inflater) in your code is a no-op.
I found a way to achieve the desired behavior by calling menu.clear(); before inflating the updated layout. I am still wondering if there is a built-in way to achieve this with the new navigation system.
In the destination Fragment I am using this now:
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater)
{
super.onCreateOptionsMenu(menu, inflater);
menu.clear();
inflater.inflate(R.menu.toolbar_items_idle, menu);
}

How do I remove a menu item on the fly?

My Android app has a navigation drawer with a menu. In the free version of the app, I want to have a menu item to allow the user to Upgrade to the paid version. Obviously I don't want this in the paid version.
How do I hide the menu item in the paid version?
The menu looks like this:
<?xml version="1.0" encoding="utf-8"?>
<menu
xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="#+id/action_home"
android:icon="#drawable/btn_home"
android:title="#string/nav_home"
/>
<item
android:id="#+id/action_acc_upgrade"
android:icon="#drawable/ic_star_black"
android:title="#string/str_acc_upgrade" />
<item
android:id="#+id/action_help"
android:icon="#drawable/ic_help_black"
android:title="#string/nav_help"
/>
</menu>
In the activity, I have:
#Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
MenuInflater inflater = this.getMenuInflater();
inflater.inflate(R.menu.activity_main_drawer, menu);
if(isPaid()) {
MenuItem upgrade = menu.findItem(R.id.action_acc_upgrade);
upgrade.setVisible(false);
}
return true;
}
If I run this through the debugger, it reaches the line if(isPaid()) and then evaluates it as true, so goes into the setVisible part. The item still shows up in the menu, though.
I also tried removing the item from the menu instead of hiding it; the debugger shows that the item is removed, but then it still shows up when the menu is displayed.
How can I hide/remove this item?
Edit
I'm using a navigation drawer to hold the menu. This is set up in onCreate as follows:
// Set up toolbar
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
// Set up navigation drawer
DrawerLayout drawer = findViewById(R.id.drawer_layout);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.nav_drawer_open, R.string.nav_drawer_close);
drawer.addDrawerListener(toggle);
toggle.syncState();
I suspect that this somehow bypasses onPrepareOptionsMenu etc? Is there a way of adding a listener which is called when the "open navigation drawer" button is clicked? I can only find callbacks for the drawer being opened or closed, and they're called after the drawer has moved - I need to call them before.
You can do it in onCreate() of your activity:
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
Menu navMenu = navigationView.getMenu();
navMenu.removeItem(R.id.action_acc_upgrade);
replace nav_view with your NavigationView's id.
There are several options:
The most convenient option: create 2 different productFlavours in your build.gradle file
productFlavors {
free {
...
}
paid {
...
}
}
And then override your menu file without action_acc_upgrade item for paid flavour.
If you want change visibility programmatically, try to use onPrepareOptionsMenu instead of onCreateOptionsMenu:
#Override
public void onPrepareOptionsMenu(Menu menu) {
super.onPrepareOptionsMenu(menu);
if(isPaid()) {
MenuItem upgrade = menu.findItem(R.id.action_acc_upgrade);
upgrade.setEnabled(false);
upgrade.setVisible(false);
}
}
If you need to change your menu after creation, invoke invalidateOptionsMenu().
You should override onPrepareOptionsMenu like this:
#Override
public void onPrepareOptionsMenu(Menu menu) {
super.onPrepareOptionsMenu(menu);
if(isPaid()) {
menu.findItem(R.id.action_settings).setVisible(false);
}
}
Notice:
Ensure get right value of isPaid() before onPrepareOptionsMenu callback, such as in onCreate() or onResume().
If it's on the fly, you need to override onPrepareOptionsMenu and call invalidateOptionsMenu if applicable:
#Override public void onPrepareOptionsMenu(Menu menu) {
super.onPrepareOptionsMenu(menu);
menu.findItem(R.id.action_acc_upgrade).setVisible(!isPaid());
}
See Activity.onPrepareOptionsMenu:
Prepare the Screen's standard options menu to be displayed. This is
called right before the menu is shown, every time it is shown. You can
use this method to efficiently enable/disable items or otherwise
dynamically modify the contents.

My app has an action bar, but no menu.xml. How do I modify my action bar?

Hello and thanks for reading,
When I first made my project, I was prompted by Android Studio to chose a boiler plate. I chose empty activity (the one without FAB and others). Still, my app has an ActionBar, but it just shows the name. Now, I want to modify that action bar and add a menu. My java extends AppCompatActivity, so there is an action bar. However, unlike my prior experiences in eclipse, there is no menu xml to that I can locate.
How can I add one or modify my action by through other means? Can I add one manually?
Thanks!
1) You need to create (or modify if it exist) your menu resources file, /res/menu/main_menu.xml to create the actions.
eg:
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:id="#+id/action_refresh"
android:showAsAction="always"
android:icon="#drawable/ic_action_refresh"
android:title="Refresh"/>
<item
android:id="#+id/action_settings"
android:showAsAction="always"
android:icon="#drawable/ic_action_setting"
android:title="Settings">
</item>
</menu>
2) Override onCreateOptionsMenu() in your activity to allows to inflate actions defined in your XML:
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main_menu, menu);
return true;
}
3) Override onOptionsItemSelected() to react the actions selection:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_refresh:
Toast.makeText(this, "Refresh selected", Toast.LENGTH_SHORT).show();
break;
case R.id.action_settings:
Toast.makeText(this, "Settings selected", Toast.LENGTH_SHORT).show();
break;
}
return true;
}

Whenever I try to add a button to my actionbar, the items are added under the overflow menu

I am trying to add a simple button to my action bar, but when I try to use the following code, the items are added as items under the overflow menu, not on the actionbar itself. Any help would be appreciated,
Jacob
Here is my Java:
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu items for use in the action bar
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu_review, menu);
return super.onCreateOptionsMenu(menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle presses on the action bar items
switch (item.getItemId()) {
case android.R.id.home:
super.onBackPressed();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
and my XML:
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:yourapp="http://schemas.android.com/apk/res-auto">
<item android:id="#+id/seda"
android:icon="#drawable/redpinreal"
android:title="Hello Worldh"
android:showAsAction="withText|always"/>
</menu>
I also have this enabled:
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
Part of your code (android:showAsAction, instead of yourapp:showAsAction) is attempting to use the native action bar. Part of your code (getSupportActionBar(), instead of getActionBar()) is attempting to use the appcompat-v7 action bar backport. Choose one and stick with it.

Creating a New button Android

I am trying to create a New button (icon only) next to the 3 dots button in the ActionBar. This is the code I tried, but it adds it as child of the 3 dots button.
main_activity_actions.xml:
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:id="#+id/create_game"
android:menuCategory="container"
android:orderInCategory="1"
android:title="#string/new_game"
android:titleCondensed="nieuw spel">
</item>
</menu>
MainActivity.java:
#Override
public boolean onCreateOptionsMenu(Menu menu)
{
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main_activity_actions, menu);
return true;
}
Also, how can I find out what default icons I can use?
To show icons in the action bar, you can add the line android:showAsAction="always" to your XML item. Still Android would show it only if it judges there is adequate space in the action bar. If you strictly always want to show your button, you can define and set a custom layout for your action bar.
You can download the default icon set for action bar from https://developer.android.com/design/downloads/index.html
try it
/res/menu/activity_main.xml
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:id="#+id/menu_settings"
android:showAsAction="never"
android:title="#string/menu_settings"/>
<item
android:id="#+id/menu_save"
android:showAsAction="ifRoom"
android:icon="#android:drawable/ic_menu_save"
android:title="#string/menu_guardar"/>
<item
android:id="#+id/menu_new"
android:showAsAction="ifRoom|withText"
android:icon="#android:drawable/ic_menu_add"
android:title="#string/menu_nuevo"/>
</menu>
MainActivit.class
public class MainActivity extends Activity {
//...
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
}
//onClic item
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_new:
Log.i("ActionBar", "Nuevo!");
return true;
case R.id.menu_save:
Log.i("ActionBar", "Guardar!");;
return true;
case R.id.menu_settings:
Log.i("ActionBar", "Settings!");;
return true;
default:
return super.onOptionsItemSelected(item);
}
}
And you can download All IconPack here:
https://developer.android.com/design/downloads/index.html
Yes, you can inflate a custom actionbar for adding buttons with images like this:
#Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LayoutInflater inflater = (LayoutInflater) getActionBar()
.getThemedContext()
.getSystemService(LAYOUT_INFLATER_SERVICE);
View customActionBarView = inflater.inflate(R.layout.actionbar_custom, null);
ActionBar actionBar = getActionBar();
actionBar.setDisplayOptions(
ActionBar.DISPLAY_SHOW_CUSTOM,
ActionBar.DISPLAY_SHOW_CUSTOM | ActionBar.DISPLAY_SHOW_HOME | ActionBar.DISPLAY_SHOW_TITLE);
actionBar.setCustomView(customActionBarView,
new ActionBar.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT));
setContentView(R.layout.activity_main);
}
Where _actionbar_custom.xml_ would be your layout resource, usually a LinearLayout with whatever components you want.

Categories