Android actionbar menu item - android

I have a item menu (sorting list) in my actionbar that I have to set its visibility to VISIBLE / GONE (depending on the list size -> empty or not).
So what I need is to check if listview is empty or not and set the visibility of that menu item accordingly, and I managed to came up with some code to do that (check listview size in onCreateOptionsMenu and set menu item visibility), but the problem is that the list can change its content both from same activity or from another, leaving me no option (IMO) than to check again listview size and set visiblity in onResume().
Here comes next problem: setting visibility of that item in onResume(), will throw a NPE, as I don't yet have that MenuItem initialized (onCreateOptionsMenu is called after onResume).
Any ideas on how to solve this situation would be appreciated.
#Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
getSupportMenuInflater().inflate(R.menu.main, menu);
/*
* initialize sortMenuItem so it can be used for turning visibility
* on/off in onResume()
*/
sortMenuItem = menu.findItem(R.id.menu_sort);
return true;
}
#Override
public void onResume() {
super.onResume();
boolean isListEmpty = mInterviewsList.isEmpty();
Log.d(LOG_TAG, "sortMenuItem is null? " + (sortMenuItem == null));
// sortMenuItem is indeed null
sortMenuItem.setVisible(isListEmpty);
sortMenuItem.setEnabled(!isListEmpty);
this.invalidateOptionsMenu();
}

You can add sortMenuItem dynamicaly in onCreateOptionsMenu depending on your listview size and in onResume call supportInvalidateOptionsMenu() if you use (google ActionBar compat lib) or similar method.

Related

What is safe to put in OnCreateOptionsMenu in Android Activity?

In my app I have a Spinner as a menu item in the action bar of my Activity. It has the collapsible action view so it appears only when the icon is clicked. I obtain a reference to my Spinner like this:
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.my_menu, menu);
spinner = (Spinner)menu.findItem(R.id.spinner).getActionView();
spinner.setAdapter(spinnerAdapter);
return true;
}
I have been reading about when OnCreateOptionsMenu is called and answers vary, with some saying it's called during onCreate. The problem is the spinnerAdapter is initialized in onCreate, and more importantly, the ArrayList containing the data for the Spinner is initialized and populated from a Room database in onCreate. So my question is, is it possible that the code from OnCreateOptionsMenu gets executed before some of the code in onCreate?

Android setting share option visibility on fragments managed by tabs in sliding tab layout

I have been struggling to implement switching visibility of Share option on Menu between fragments. I am using sliding tab layout and has a fragment in each of the 2 tabs. First tab (uses list view) and when an item is selected, I am setting a flag as true and calls invalidateOptionsMenu() and it works fine by showing a share option on the App bar menu, but I am not able to cancel it when I move to the other fragment which has mainly preferences. Code is similar to the below.
public void setSharedIntentText(String text) {
sharedText = text;
if (shareOptionVisibility == false) {
shareOptionVisibility = true;
invalidateOptionsMenu();
}
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
// Locate MenuItem with ShareActionProvider
MenuItem shareItem = menu.findItem(R.id.menu_share);
// Fetch and store ShareActionProvider
mShareActionProvider = (ShareActionProvider) MenuItemCompat.getActionProvider(shareItem);
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.setType("text/plain");
sendIntent.putExtra(Intent.EXTRA_TEXT, sharedText);
mShareActionProvider.setShareIntent(sendIntent);
shareItem.setVisible(shareOptionVisibility);
When I switch between tabs, visibility should be set appropriately. I tried to set it onPause method of the first fragment, and then onResume method of second fragment, but control doesn't seem to go these methods when I look at the logcat. The code I have used to set visibility to false is as below in fragment2.
public void onResume() {
super.onResume();
Log.i(TAG, "On Resume ");
((MainActivity) getActivity()).shareOptionVisibility = false;
((MainActivity) getActivity()).invalidateOptionsMenu();
}
So would like to know where is the best place to put the code to control visibility when we switch between tabs. Here are the list of classes I use.
MainActivity, fragment1, fragment2, SlidingTabLayout, SlidingTabStrip and ViewPagerAdaptor. This code was implemented on top of the com.example.android.actionbarcompat.shareactionprovider example.
Thanks in advance
Issue now resolved by implementing the onCreateOptionsMenu method from the fragment rather than from the MainActivity.
Thanks

Access Fragment's Menu within a FragmentStatePagerAdapter

I use a FragmentStatePagerAdapter to display fragments inside a ViewPager.
These fragments display 2 additional icons on top of the ones coming from the parent Activity.
These 2 icons are showed/hidden according to fragment displayed, so I tried to keep the Menu inflated in memory in order to modify it dynamically.
On my ViewPager, 3 fragments are always loaded, only the middle one is displayed.
The problem is the following: it seems that onCreateOptionsMenu and onPrepareOptionsMenu are called only for the first Fragment created, because of this, I get null pointers when I try to get the menu on the other fragments. Please see the code below:
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
//Get the 2 icons for the rates
inflater.inflate(R.menu.rate_fragment, menu);
//Get activity's icons
super.onCreateOptionsMenu(menu, inflater);
mMenu = menu;
}
Here are the functions I use to hide/show the menu items:
private void hideOption(int id){
MenuItem item = mMenu.findItem(id);
if(item != null){
item.setVisible(false);
}
}
private void showOption(int id){
MenuItem item = mMenu.findItem(id);
if(item != null){
item.setVisible(true);
}
}
But these functions fail as soon as the system tries to load the second Fragment.
My guess is that the menu is only created once for the FragmentStatePagerAdapter, but then how can I modify dynamically the menu? Do I have to modify it using the Activity?
Thanks!

ActionBarSherlock - Indeterminate Progress

It's clear that for showing/hiding the indeterminate progress you have to use this method:
itemMenu.setActionView(...);
So:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_refresh:
item.setActionView(R.layout.indeterminate_progress_action);
runAsyncTask();
...
}
}
What is not clear to me is: how to set the action view back to null. I don't want to keep a reference to a MenuItem, I don't think it is correct since I don't want to assume anything about the OptionsMenu lifecycle.
How should I set back the action view to null on onPostExecute?
I do it like this :
refresh = false; // the future state of your indeterminate progress
invalidateOptionsMenu(); // trigger the recreation of the menu and call onCreateOptionsMenu(Menu)
then in your onCreateOptionsMenu(Menu) method :
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater)
{
super.onCreateOptionsMenu(menu, inflater);
MenuItem refreshItem = menu.add(Menu.NONE, R.id.action_bar_refresh, 1, "Refresh");
refreshItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
if(refresh)
refreshItem.setActionView(R.layout.indeterminate_progress_action);
else
refreshItem.setIcon(R.drawable.ic_menu_refresh);
}
How about invalidateOptionsMenu()? Your onCreateOptionsMenu() would probably always set it to null, then.
I believe you could just call setActionView(null) on that MenuItem
Then refresh the ActionBar with invalidateOptionsMenu()
There is no need to manipulate specific menu items if you would prefer not to.
I use a different approach that leverages off the system's indeterminate progress bar functionality (as ported to ActionBarSherlock). I explain it here to offer more options to future readers to use whichever way works best for them.
My base fragment has a method I call to turn my loading UI on & off. Here is a trimmed down version:
private void setLoading(final boolean isLoading)
{
final SherlockFragmentActivity sherlockActivity = getSherlockActivity();
sherlockActivity.runOnUiThread(new Runnable()
{
public void run()
{
// show loading progress bar
sherlockActivity
.setSupportProgressBarIndeterminateVisibility(isLoading);
// hide the rest of the menu
setMenuVisibility(!isLoading);
}
});
}
For this to work, your activity must be configured to use the correct style - call this from your SherlockFragmentActivity.onCreate() method:
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
The final trick is that on pre-HoneyComb devices, this causes the progress bar to show immediately by default (instead of being hidden by default from HC & above).
you must set it to be invisible
you must also create a Sherlock Action Bar instance before this code will work
The onCreate() thus becomes:
protected void onCreate(Bundle arg0)
{
super.onCreate(arg0);
// allow window to show progress spinner in the action bar
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
getSupportActionBar();
setSupportProgressBarIndeterminateVisibility(false);
}
For more details on this you can check my answer to
Intermediate Progress doesn't work with ActionBarSherlock running on Gingerbread (here).
If you don't want to keep a reference to the menu item, then you can simply keep a reference to the Menu object instead. A reference to the Menu is guaranteed to remain valid until the next time onCreateOptionsMenu() is called as mentioned in the docs (http://developer.android.com/reference/android/app/Activity.html#onCreateOptionsMenu(android.view.Menu)).
Then call:
MenuItem menuItem = mMenu.findItem(R.id.favourite_payment);
menuItem.setActionView(null);
Or alternatively if using AppCompat:
MenuItem menuItem = mMenu.findItem(R.id.favourite_payment);
MenuItemCompat.setActionView(menuItem, null);
There is no need to call invalidateOptionsMenu().

How to update a menu item shown in the ActionBar?

I have an Activity that has 2 fragments. Both are ListFragments and both contribute MenuItems to the Menu. I have one MenuItem that I've set the attribute android:showAsAction to have it show as a button on the ActionBar. Which works fine.
Now the MenuItem is state dependent. It's a Pause/Resume menu option for pausing and resuming a queue. My problem is I can't figure out how to set it's initial statue when the Fragment is created.
It's state is dependent on the whether the queue is paused or not. So I have an AsyncTask that gets the queue and sets a boolean (paused) based on the state of the queue. I'm calling onPrepareOptionsMenu to set the text for the Pause menu item based on the last known state of the queue and this works great if I leave the MenuItem in the actual menu. You tap the menu icon and onPrepareOptionsMenu is fired and the menu is updated before it's displayed.
The problem is, if I put that same MenuItem on the ActionBar (showAsAction), how can I force it to update without having to call onPrepareOptionsMenu? I need to be able to do this because on first launch of the app, I send a request to get the queue, but the task returns after the ActionBar is setup and displayed. I've created a handler in my fragment that gets called every time I get a queue update, but from there, how can I update the text for my MenuItem on the ActionBar? I can't seem to find a way to get the currently set Menu to manipulate it except for in onPrepareOptionMenu.
Rob W.
Option #1: Try invalidateOptionsMenu(). I don't know if this will force an immediate redraw of the action bar or not.
Option #2: See if getActionView() returns anything for the affected MenuItem. It is possible that showAsAction simply automatically creates action views for you. If so, you can presumably enable/disable that View.
I can't seem to find a way to get the currently set Menu to manipulate it except for in onPrepareOptionMenu.
You can hang onto the Menu object you were handed in onCreateOptionsMenu(). Quoting the docs:
You can safely hold on to menu (and any items created from it), making modifications to it as desired, until the next time onCreateOptionsMenu() is called.
in my case: invalidateOptionsMenu just re-setted the text to the original one,
but directly accessing the menu item and re-writing the desire text worked without problems:
if (mnuTopMenuActionBar_ != null) {
MenuItem mnuPageIndex = mnuTopMenuActionBar_
.findItem(R.id.menu_magazin_pageOfPage_text);
if (mnuPageIndex != null) {
if (getScreenOrientation() == 1) {
mnuPageIndex.setTitle((i + 1) + " von " + pages);
}
else {
mnuPageIndex.setTitle(
(i + 1) + " + " + (i + 2) + " " + " von " + pages);
}
// invalidateOptionsMenu();
}
}
due to the comment below, I was able to access the menu item via the following code:
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.magazine_swipe_activity, menu);
mnuTopMenuActionBar_ = menu;
return true;
}
To refresh menu from Fragment simply call:
getActivity().invalidateOptionsMenu();
I have used this code:
public boolean onPrepareOptionsMenu (Menu menu) {
MenuInflater inflater = getMenuInflater();
TextView title = (TextView) findViewById(R.id.title);
menu.getItem(0).setTitle(
getString(R.string.payFor) + " " + title.getText().toString());
menu.getItem(1).setTitle(getString(R.string.payFor) + "...");
return true;
}
And worked like a charm to me you can find OnPrepareOptionsMenu here
First please follow the two lines of codes to update the action bar items
before that you should set a condition in oncreateOptionMenu().
For example:
Boolean mISQuizItemSelected = false;
/**
* Called to inflate the action bar menus
*
* #param menu
* the menu
*
* #return true, if successful
*/
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu items for use in the action bar
inflater.inflate(R.menu.menu_demo, menu);
//condition to hide the menus
if (mISQuizItemSelected) {
for (int i = 0; i < menu.size(); i++) {
menu.getItem(i).setVisible(false);
}
}
return super.onCreateOptionsMenu(menu);
}
/**
* Called when the item on the action bar being selected.
*
* #param item
* menuitem being selected
*
* #return true if the menuitem id being selected is matched
* false if none of the menuitems id are matched
*/
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getId() == R.id.action_quiz) {
//to navigate based on the usertype either learner or leo
mISQuizItemSelected = true;
ActionBar actionBar = getActionBar();
invalidateOptionMenu();
}
}
For clarity, I thought that a direct example of grabbing onto a resource can be shown from the following that I think contributes to the response for this question with a quick direct example.
private MenuItem menuItem_;
#Override
public boolean onCreateOptionsMenu(Menu menuF)
{
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu_layout, menuF);
menuItem_ = menuF.findItem(R.id.menu_item_identifier);
return true;
}
In this case you hold onto a MenuItem reference at the beginning and then change the state of it (for icon state changes for example) at a later given point in time.

Categories

Resources