Popup menu with icon on Android - android

My menu xml code menu.xml:
<?xml version="1.0" encoding="utf-8"?><menu xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Single menu item
Set id, icon and Title for each menu item
-->
<item android:id="#+id/back"
android:icon="#drawable/back1"
android:showAsAction="never"
android:title="Back" />
<item android:id="#+id/My_Profile"
android:icon="#drawable/myprofile"
android:showAsAction="never"
android:title="My Profile" />
<item android:id="#+id/Job_Alert"
android:icon="#drawable/jobalert4"
android:showAsAction="never"
android:title="Job Alert !" />
<item android:id="#+id/saved_job"
android:icon="#drawable/jobapplied"
android:title="Saved Jobs"
/>
<item android:id="#+id/Logout"
android:icon="#drawable/logout"
android:title="Logout" />
</menu>
I am calling menu xml like this
PopupMenu popup = new PopupMenu(getBaseContext(), v);
popup.getMenuInflater().inflate(R.menu.menu, popup.getMenu());
popup.show();
But it does not show the icon.
How can I set the icon on the popup menu?

You can create popup menu with icon using the MenuBuilder and MenuPopupHelper.
MenuBuilder menuBuilder =new MenuBuilder(this);
MenuInflater inflater = new MenuInflater(this);
inflater.inflate(R.menu.menu, menuBuilder);
MenuPopupHelper optionsMenu = new MenuPopupHelper(this, menuBuilder, view);
optionsMenu.setForceShowIcon(true);
// Set Item Click Listener
menuBuilder.setCallback(new MenuBuilder.Callback() {
#Override
public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) {
switch (item.getItemId()) {
case R.id.opt1: // Handle option1 Click
return true;
case R.id.opt2: // Handle option2 Click
return true;
default:
return false;
}
}
#Override
public void onMenuModeChange(MenuBuilder menu) {}
});
optionsMenu.show();
menu.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="#+id/opt1"
android:icon="#mipmap/ic_launcher"
android:title="option 1" />
<item
android:id="#+id/opt2"
android:icon="#mipmap/ic_launcher"
android:title="option 2" />
</menu>

You can enable icons for popup menu by using Java reflection to call a hidden method as below:
public static void setForceShowIcon(PopupMenu popupMenu) {
try {
Field[] fields = popupMenu.getClass().getDeclaredFields();
for (Field field : fields) {
if ("mPopup".equals(field.getName())) {
field.setAccessible(true);
Object menuPopupHelper = field.get(popupMenu);
Class<?> classPopupHelper = Class.forName(menuPopupHelper
.getClass().getName());
Method setForceIcons = classPopupHelper.getMethod(
"setForceShowIcon", boolean.class);
setForceIcons.invoke(menuPopupHelper, true);
break;
}
}
} catch (Throwable e) {
e.printStackTrace();
}
}

It's because when you use the showAsAction="never" attribute, the default overflow does not return your icon. You could create your own overflow like this:
<item android:title=""
android:id="#+id/overflow"
android:showAsAction="always"
android:icon="#drawable/overflow_icon">
<menu >
<item android:id="#+id/back"
android:icon="#drawable/back1"
android:title="Back" />
<item android:id="#+id/My_Profile"
android:icon="#drawable/myprofile"
android:title="My Profile" />
<item android:id="#+id/Job_Alert"
android:icon="#drawable/jobalert4"
android:title="Job Alert !" />
<item android:id="#+id/saved_job"
android:icon="#drawable/jobapplied"
android:title="Saved Job"/>
<item android:id="#+id/Logout"
android:icon="#drawable/logout"
android:title="Logout" />
</menu>
</item>

You could use reflection as described here:
https://stackoverflow.com/a/18431605/4521603
Or if you use Xamarin / C#:
add:
using Java.Lang.Reflect;
Then use this in your code:
PopupMenu puMenu = new PopupMenu(Activity, v)
Field field = puMenu.Class.GetDeclaredField("mPopup");
field.Accessible = true;
Java.Lang.Object menuPopupHelper = field.Get(puMenu);
Method setForceIcons = menuPopupHelper.Class.GetDeclaredMethod("setForceShowIcon", Java.Lang.Boolean.Type);
setForceIcons.Invoke(menuPopupHelper, true);
puMenu.Inflate (Resource.Menu.your_actions);
puMenu.Show ();

Use this:
/**
* Copied from android.support.v7.widget.PopupMenu.
* "mPopup.setForceShowIcon(true);" in the constructor does the trick :)
*
* #author maikvlcek
* #since 5:00 PM - 1/27/14
*/
public class IconizedMenu implements MenuBuilder.Callback, MenuPresenter.Callback {
private Context mContext;
private MenuBuilder mMenu;
private View mAnchor;
private MenuPopupHelper mPopup;
private OnMenuItemClickListener mMenuItemClickListener;
private OnDismissListener mDismissListener;
/**
* Callback interface used to notify the application that the menu has closed.
*/
public interface OnDismissListener {
/**
* Called when the associated menu has been dismissed.
*
* #param menu The PopupMenu that was dismissed.
*/
public void onDismiss(IconizedMenu menu);
}
/**
* Construct a new PopupMenu.
*
* #param context Context for the PopupMenu.
* #param anchor Anchor view for this popup. The popup will appear below the anchor if there
* is room, or above it if there is not.
*/
public IconizedMenu(Context context, View anchor) {
mContext = context;
mMenu = new MenuBuilder(context);
mMenu.setCallback(this);
mAnchor = anchor;
mPopup = new MenuPopupHelper(context, mMenu, anchor);
mPopup.setCallback(this);
mPopup.setForceShowIcon(true);
}
/**
* #return the {#link android.view.Menu} associated with this popup. Populate the returned Menu with
* items before calling {#link #show()}.
*
* #see #show()
* #see #getMenuInflater()
*/
public Menu getMenu() {
return mMenu;
}
/**
* #return a {#link android.view.MenuInflater} that can be used to inflate menu items from XML into the
* menu returned by {#link #getMenu()}.
*
* #see #getMenu()
*/
public MenuInflater getMenuInflater() {
return new SupportMenuInflater(mContext);
}
/**
* Inflate a menu resource into this PopupMenu. This is equivalent to calling
* popupMenu.getMenuInflater().inflate(menuRes, popupMenu.getMenu()).
* #param menuRes Menu resource to inflate
*/
public void inflate(int menuRes) {
getMenuInflater().inflate(menuRes, mMenu);
}
/**
* Show the menu popup anchored to the view specified during construction.
* #see #dismiss()
*/
public void show() {
mPopup.show();
}
/**
* Dismiss the menu popup.
* #see #show()
*/
public void dismiss() {
mPopup.dismiss();
}
/**
* Set a listener that will be notified when the user selects an item from the menu.
*
* #param listener Listener to notify
*/
public void setOnMenuItemClickListener(OnMenuItemClickListener listener) {
mMenuItemClickListener = listener;
}
/**
* Set a listener that will be notified when this menu is dismissed.
*
* #param listener Listener to notify
*/
public void setOnDismissListener(OnDismissListener listener) {
mDismissListener = listener;
}
/**
* #hide
*/
public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) {
if (mMenuItemClickListener != null) {
return mMenuItemClickListener.onMenuItemClick(item);
}
return false;
}
/**
* #hide
*/
public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
if (mDismissListener != null) {
mDismissListener.onDismiss(this);
}
}
/**
* #hide
*/
public boolean onOpenSubMenu(MenuBuilder subMenu) {
if (subMenu == null) return false;
if (!subMenu.hasVisibleItems()) {
return true;
}
// Current menu will be dismissed by the normal helper, submenu will be shown in its place.
new MenuPopupHelper(mContext, subMenu, mAnchor).show();
return true;
}
/**
* #hide
*/
public void onCloseSubMenu(SubMenuBuilder menu) {
}
/**
* #hide
*/
public void onMenuModeChange(MenuBuilder menu) {
}
/**
* Interface responsible for receiving menu item click events if the items themselves
* do not have individual item click listeners.
*/
public interface OnMenuItemClickListener {
/**
* This method will be invoked when a menu item is clicked if the item itself did
* not already handle the event.
*
* #param item {#link MenuItem} that was clicked
* #return <code>true</code> if the event was handled, <code>false</code> otherwise.
*/
public boolean onMenuItemClick(MenuItem item);
}
}
Source: https://gist.github.com/mediavrog/9345938

The setForceShowIcon function is now public and not restricted anymore so this works!
private fun showPopupMenu(view: View) {
PopupMenu(this, view).apply {
menuInflater.inflate(R.menu.my_menu, menu)
setForceShowIcon(true)
}.show()
}

if trying this code in any activity then replace getbBaseContext() with this i.e activity context
PopupMenu popup = new PopupMenu(this, v);

before popupMenu.show(); use
try {
Field mFieldPopup=popupMenu.getClass().getDeclaredField("mPopup");
mFieldPopup.setAccessible(true);
MenuPopupHelper mPopup = (MenuPopupHelper) mFieldPopup.get(popupMenu);
mPopup.setForceShowIcon(true);
} catch (Exception e) {
}

You can implement this By the use of Reflection if u don`t familiar with it with the help of this awesome java advanced feature u can modify the runtime behavior of applications running in the JVM you can look at the object and perform its methods on runtime and in our case we need to modify popupMenu behavior at runtime instead of extend the core class and modify it ;) hope that help Try my method working like a charm
private void showPopupMenu(View view) {
// inflate menu
PopupMenu popup = new PopupMenu(mcontext, view);
MenuInflater inflater = popup.getMenuInflater();
inflater.inflate(R.menu.main, popup.getMenu());
Object menuHelper;
Class[] argTypes;
try {
Field fMenuHelper = PopupMenu.class.getDeclaredField("mPopup");
fMenuHelper.setAccessible(true);
menuHelper = fMenuHelper.get(popup);
argTypes = new Class[]{boolean.class};
menuHelper.getClass().getDeclaredMethod("setForceShowIcon", argTypes).invoke(menuHelper, true);
} catch (Exception e) {
}
popup.show();
}

Related

Show Spinner from action bar - Android

I think I'm missing an important part in understanding how to call the spinner from the action bar, considering that apparently the callbacks onItemSelected and onNothingSelected apparently are not being called.
Can someone give an idea please? I've read plenty of other questions like these but didn't find the solution.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps);
// Confifure the spinner for radius selection.
setUpSpinner();
}
/**
* Set up the spinner.
* */
public void setUpSpinner(){
// Instantiate the spinner.
mSpinner = new Spinner(this);
// Create an ArrayAdapter using the string array and a default spinner layout.
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this,
R.array.radius_config, android.R.layout.simple_spinner_item);
// Specify the layout to use when the list of choices appears.
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
// Apply the adapter to the spinner
mSpinner.setAdapter(adapter);
mSpinner.setOnItemSelectedListener(this);
}
/**
* Called when the user pressed the menu button.
* */
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu items for use in the action bar.
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main_activity_actions, menu);
return super.onCreateOptionsMenu(menu);
}
/**
* Called when the user clicks at an item on the menu.
* */
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle presses on the action bar items
switch (item.getItemId()) {
case R.id.radius_config:
mSpinner.performClick();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
/**
* Spinner callback, when an item on the spinner is clicked.
* */
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
Log.d("map values", "Position: " + position);
}
/**
* Spinner callback, when no iten is selected.
* */
#Override
public void onNothingSelected(AdapterView<?> parent) {
Log.d("map values", "Nothing");
}

Physical Menu / Overflow Button Unresponsive in Certain Views

I'm having some weird, inconsistent behaviour regarding the physical menu button in my application.
The following may or may not be helpful:
I have an app which changes its UI dependent on the device + screen size + orientation. On tablets in a landscape orientation, I use an activity with 2 fragments viewed simultaneously (contacts list + the chat of the selected contact). On phones, and on the tablet in portrait orientation, I instead use 2 separate activities; one for the contacts list and one for the chat.
I mention this because of the following weird behaviour that I am observing: the physical menu button on my devices is unresponsive in my app on both the phone, and on the tablets portrait orientation. When the tablet is in landscape orientation, the physical button does work as expected (which is show the overflow menu of my action bar). The menu button works correctly outside of my app.
I originally thought the issue was with my phone's version of android, but given that I'm also seeing the problem with the tablet in the portrait orientation, I'm not sure where the problem might lie. I did not hardcode any code for the physical menu button, so it shouldn't be a case of some functionality not being appropriately replicated for the single-pane view of the phone and portrait-oriented tablet.
Any ideas or answers would be greatly appreciated!
Thanks
EDIT: Added requested code.
The portrait orientation activity:
package com.h.r.android.tcip;
import android.content.ComponentName;
import android.content.ContentUris;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.database.ContentObserver;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.support.v4.app.Fragment;
import android.util.Log;
import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuItem;
import com.h.r.android.tctip.ConversationFragment.Builder;
import com.h.r.android.tctip.data.TacMessage;
import com.h.r.android.tctip.db.AddressmessageSchema;
import com.h.r.android.tctip.settings.PreferencesHelper;
public class ConversationActivity extends LoggedInTCActivity {
#SuppressWarnings("unused")
private final String TAG = ConversationActivity.class.getSimpleName();
/**
* Projection for address database query results.
*/
protected static final String[] ADDRESS_PROJECTION = new String[] {
AddressmessageSchema.UID, AddressmessageSchema.HANDLE };
/**
* The TCService running in the background doing the send/receive work.
*/
protected TCService mService;
/**
* Handler used for the partner handle cursor.
*/
protected final Handler mHandler = new Handler();
/**
* Used to track partner handle changes.
*/
protected ContentObserver mHandleObserver = new ContentObserver(mHandler) {
/*
* (non-Javadoc)
*
* #see android.database.ContentObserver#onChange(boolean)
*/
#Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
getSupportActionBar().setTitle(getPartnerHandle());
}
};
/**
* The actual partner ID, from the intent.
*/
static long mPartnerId;
/**
* The connection binding us to the Service. We're using this to
* indicate to Android the dependency between this Activity and the running
* Service.
*/
protected final ServiceConnection mConnection = new ServiceConnection() {
/*
* (non-Javadoc)
*
* #see
* android.content.ServiceConnection#onServiceDisconnected(android.content
* .ComponentName)
*/
public void onServiceDisconnected(ComponentName name) {
mService = null;
}
/*
* (non-Javadoc)
*
* #see
* android.content.ServiceConnection#onServiceConnected(android.content
* .ComponentName, android.os.IBinder)
*/
public void onServiceConnected(ComponentName name, IBinder service) {
mService = ((TCService.TCServiceBinder) service)
.getService();
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setTheme(PreferencesHelper.getThemeId(this));
ConversationFragment frag = new ConversationFragment.Builder(
getIntent().getExtras()).build();
setContentView(R.layout.tc_conv);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
/*
if (savedInstanceState != null)
{
mPartnerId = savedInstanceState.getLong("mPartnerId", mPartnerId);
}
else{
*/
// The Fragment's partnerId
mPartnerId = frag.getPartnerId();
//}
getSupportActionBar()
.setTitle(
mPartnerId == 0 ? getString(R.string.tc_all_users_chat)
: getPartnerHandle());
getSupportFragmentManager().beginTransaction()
.add(R.id.conversation, frag).commit();
}
#Override
protected void onResume() {
super.onResume();
startService(new Intent(this, TCService.class));
//startService(new Intent(this, DiscoveryService.class));
// bind to the service to disable notifications while this is up
bindService(new Intent(this, TCService.class), mConnection, 0);
if (mPartnerId != 0) {
Uri handleUri = ContentUris.withAppendedId(TacMessage.ADDRESS_URI,
mPartnerId);
getContentResolver().registerContentObserver(handleUri, true,
mHandleObserver);
mHandleObserver.onChange(true);
}
}
/*
* (non-Javadoc)
*
* #see android.support.v4.app.FragmentActivity#onPause()
*/
#Override
protected void onPause() {
if (mService != null) {
unbindService(mConnection);
}
if (mPartnerId != 0) {
getContentResolver().unregisterContentObserver(mHandleObserver);
}
super.onPause();
}
/**
* Get the partner handle to show in the action bar.
*
* #return
*/
protected String getPartnerHandle() {
// Generic default in case something goes wrong.
String partnerHandle = getString(R.string.t_c_app_name);
Cursor c = null;
try {
String selection = AddressmessageSchema.UID + " = ?";
String[] selectionArguments = { "" + mPartnerId };
c = getContentResolver().query(TacMessage.ADDRESS_URI,
ADDRESS_PROJECTION, selection, selectionArguments, null);
if (c != null && c.moveToFirst()) {
partnerHandle = c.getString(c
.getColumnIndex(AddressmessageSchema.HANDLE));
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (c != null) {
c.close();
}
}
return partnerHandle;
}
/*
* Can be called from screen orientation change or keyboard hidden. This is
* being used to prevent the Activity from being destroyed or rebuilt so
* that during zip and image conversion activities, we don't end up killing
* the app by rotating the screen and such.
*
* (non-Javadoc)
*
* #see
* android.support.v4.app.FragmentActivity#onConfigurationChanged(android
* .content.res.Configuration)
*/
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE)
{
//Builder.CONTACT_UID = getString((int) mPartnerId);
Log.d("gabe", "the config is changing in convo activity" + mPartnerId);
//finish();
}
// Pass in the orientation of sensor so that we keep receiving these
// calls.
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);
}
public void onDestroy(Bundle savedInstanceState)
{
Log.d("gabe", "the conver activity is being destroyed" + mPartnerId);
}
public void onSaveInstance(Bundle savedInstanceState)
{
Log.d("gabe", "the con act is c saving instance");
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// TODO Auto-generated method stub
getSupportMenuInflater().inflate(R.menu.chat_only_menu, menu);
return super.onCreateOptionsMenu(menu);
}
/*
* Add the up (ancestral) navigation.
*
* (non-Javadoc)
*
* #see
* com.actionbarsherlock.app.SherlockFragmentActivity#onOptionsItemSelected
* (android.view.MenuItem)
*/
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
// Ancestral navigation (Home/Up button on Action Bar)
Intent parentActivityIntent = new Intent(this,
TCActivity.class);
// See the ancestral navigation docs about synthesizing a back
// stack, if we ever have need for more back steps than the
// TCActivity class.
// http://developer.android.com/training/implementing-navigation/ancestral.html
parentActivityIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP
| Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(parentActivityIntent);
finish();
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
public boolean onContextItemSelected(android.view.MenuItem item) {
// TODO Auto-generated method stub
Fragment fragment = (Fragment) getSupportFragmentManager().findFragmentById(R.id.conversation);
if( null != fragment ) {
fragment.onContextItemSelected(item);
}
return super.onContextItemSelected(item);
}
}
The xml for the portrait activity, probably not what you wanted
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/conversation"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
chat only xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<group
android:id="#+id/group_alert_checked"
android:checkableBehavior="all" >
<item
android:id="#+id/menu_alert"
android:checked="false"
android:icon="?attr/buttonface_alert_unchecked"
android:showAsAction="always"
android:title="#string/menu_set_alert_message_mode"/>
</group>
<item
android:id="#+id/menu_attach_existing_picture"
android:icon="?attr/buttonface_existing_picture"
android:showAsAction="always"
android:title="#string/menu_attach_existing_picture">
</item>
<item
android:id="#+id/menu_attach_new_picture"
android:icon="?attr/buttonface_new_picture"
android:showAsAction="always"
android:title="#string/menu_attach_new_picture">
</item>
<item
android:id="#+id/menu_attach_file"
android:icon="?attr/buttonface_attach_file"
android:showAsAction="always"
android:title="#string/menu_attach_file">
</item>
<item
android:icon="?attr/buttonface_overflow"
android:showAsAction="always">
<menu>
<item
android:id="#+id/menu_add"
android:showAsAction="ifRoom"
android:title="#string/menu_new_contact">
</item>
<item
android:id="#+id/menu_clear_conversation"
android:showAsAction="ifRoom"
android:title="#string/menu_clear_conversation">
</item>
<item
android:id="#+id/menu_save_conversation"
android:showAsAction="ifRoom"
android:title="#string/menu_save_conversation">
</item>
<item
android:id="#+id/menu_logout"
android:showAsAction="ifRoom"
android:title="#string/logout"/>
</menu>
</item>
</menu>
I also have the code for the fragment and the fragments xml, which might also be useful to you, but the fragment code is very large. I recognize that the xml for the activity isn't very helpful as is without the rest though. Let me know what else would help and I'll figure out a better way of sharing.
Ok, I think you need to edit your onOptionsItemSelected override to handle the different menu items, here is an example that uses an if else instead of switch as using switches has issues in library projects.
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int itemId = item.getItemId();
if (itemId == R.id.menu_alert) {
// do something here
return true;
} else if (itemId == R.id.menu_attach_existing_picture) {
// do something here
return true;
} else if (itemId == R.id.menu_attach_new_picture) {
// do something here
return true;
} else if (itemId == R.id.menu_attach_file) {
// do something here
return true;
} else if (itemId == R.id.menu_add) {
// do something here
return true;
} else if (itemId == R.id.menu_clear_conversation) {
// do something here
return true;
} else if (itemId == R.id.menu_save_conversation) {
// do something here
return true;
} else if (itemId == R.id.menu_logout) {
// do something here
return true;
} else if (itemId == android.R.id.home) {
// Ancestral navigation (Home/Up button on Action Bar)
Intent parentActivityIntent = new Intent(this,
TCActivity.class);
// See the ancestral navigation docs about synthesizing a back
// stack, if we ever have need for more back steps than the
// TCActivity class.
// http://developer.android.com/training/implementing-navigation/ancestral.html
parentActivityIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP
| Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(parentActivityIntent);
finish();
return true;
} else if (super.onOptionsItemSelected(item)) {
// parent activity handled this selection
return true;
}
return false;
}

Auto-hideable ActionBar and ShareActionProvider

I'm using native ActionBar and ShareActionProvider.
There is a code in my activity that hides ActionBar in four seconds:
Handler hideUIHandler = new Handler();
hideUIHandler.postDelayed(new Runnable() {
public void run() {
getActionBar().hide();
}
}, 4000);
Unfortunately hideUIHandler hides ActionBar even when I clicked the "Share" item to see menu providing by ShareActionProvider.
I don't want to hide ActionBar in that case. What should I do?
You can override Activity.onMenuOpened and Activity.onPanelClosed to determine when the overflow menu or other sub-menus are showing, such as the ShareActionProvider. Here's an example:
/** True if an options menu has been opened, false otherwise */
private boolean mMenuOpened;
#Override
public boolean onMenuOpened(int featureId, Menu menu) {
mMenuOpened = true;
return super.onMenuOpened(featureId, menu);
}
#Override
public void onPanelClosed(int featureId, Menu menu) {
super.onPanelClosed(featureId, menu);
mMenuOpened = false;
}
Alternatively
ActivityChooserView has a way to check ActivityChooserView.isShowingPopup, but you'll have to subclass ShareActionProvider and invoke it via reflection because the ActivityChooserView class is hidden.
Here's an example:
AccessibleShareActionProvider
/**
* A subclass of {#link ShareActionProvider} that uses reflection to invoke
* <p>
* <code>android.widget.ActivityChooserView.isShowingPopup</code>
* <p>
*/
public class AccessibleShareActionProvider extends ShareActionProvider {
/** The action view created for {#link ShareActionProvider} */
private View mActivityChooserView;
/**
* Constructor for <code>AccessibleShareActionProvider</code>
*
* #param context The {#link Context} to use
*/
public AccessibleShareActionProvider(Context context) {
super(context);
}
/**
* {#inheritDoc}
*/
#Override
public View onCreateActionView(MenuItem forItem) {
mActivityChooserView = super.onCreateActionView(forItem);
return mActivityChooserView;
}
/**
* #return True if showing, false if already dismissed
*/
public boolean isShowingPopup() {
try {
final Class<?> acv = Class.forName("android.widget.ActivityChooserView");
final Method isShowingPopup = acv.getMethod("isShowingPopup", new Class[] {});
return (boolean) isShowingPopup.invoke(mActivityChooserView, new Object[] {});
} catch (final Exception ignored) {
// Nothing to do
}
return false;
}
}
Your MenuItem
<item
android:id="#+id/menu_item_share"
android:actionProviderClass="your_path_to.AccessibleShareActionProvider"
android:showAsAction="ifRoom"
android:title="#string/share"/>
In your Activity
private Handler mHandler = new Handler();
private AccessibleShareActionProvider mShareProvider;
#Override
public boolean onCreateOptionsMenu(Menu menu) {
...
final MenuItem item = menu.findItem(R.id.menu_item_share);
mShareProvider = (AccessibleShareActionProvider) item.getActionProvider();
...
return super.onCreateOptionsMenu(menu);
}
private final Runnable mHideActionBar = new Runnable() {
#Override
public void run() {
// If the ShareActionProvider is showing, delay for 4 seconds
if (mShareProvider.isShowingPopup()) {
mHandler.removeCallbacksAndMessages(null);
mHandler.postDelayed(mHideActionBar, 4000);
return;
}
getActionBar().hide();
}
};

Action bar menu for each tab fragment with ActionBarSherlock

I am having some trouble getting an options menu working for each fragments of my activity using ActionBarSherlock API.
I have placed setHasOptionsMenu(true) inside my onCreateView, but onCreateOptionsMenu inside fragments is never called.
My Main Activity
public class EvolutionActivity extends TabActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
addTab(getResources().getString(R.string.fragment_measurement_title), TabFragmentMeasurement.class, null);
addTab(getResources().getString(R.string.fragment_workout_title) , TabFragmentWorkout.class, null);
addTab(getResources().getString(R.string.fragment_exercise_title), TabFragmentExercise.class, null);
}
}
Tab activity abstract class TabActivity.class
public abstract class TabActivity extends SherlockFragmentActivity {
private ViewPager mViewPager;
private TabsAdapter adapter;
#Override
public void onCreate(Bundle savedInstanceState) {
/*
* Create the ViewPager and our custom adapter
*/
mViewPager = new ViewPager(this);
adapter = new TabsAdapter( this, mViewPager );
mViewPager.setAdapter( adapter );
mViewPager.setOnPageChangeListener( adapter );
/*
* We need to provide an ID for the ViewPager, otherwise we will get an exception like:
*
* java.lang.IllegalArgumentException: No view found for id 0xffffffff for fragment TabFragmentMeasurement{40de5b90 #0 id=0xffffffff android:switcher:-1:0}
* at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:864)
*
* The ID 0x7F04FFF0 is large enough to probably never be used for anything else
*/
mViewPager.setId( 0x7F04FFF0 );
super.onCreate(savedInstanceState);
/*
* Set the ViewPager as the content view
*/
setContentView(mViewPager);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// TODO Auto-generated method stub
switch (item.getItemId()) {
case R.id.action_settings:{
Intent intent = new Intent(this, ParametersActivity.class);
startActivity(intent);
break;
}
}
return super.onOptionsItemSelected(item);
}
/**
* Add a tab with a backing Fragment to the action bar
* #param titleRes A string resource pointing to the title for the tab
* #param fragmentClass The class of the Fragment to instantiate for this tab
* #param args An optional Bundle to pass along to the Fragment (may be null)
*/
protected void addTab(int titleRes, Class fragmentClass, Bundle args ) {
adapter.addTab( getString( titleRes ), fragmentClass, args );
}
/**
* Add a tab with a backing Fragment to the action bar
* #param titleRes A string to be used as the title for the tab
* #param fragmentClass The class of the Fragment to instantiate for this tab
* #param args An optional Bundle to pass along to the Fragment (may be null)
*/
protected void addTab(CharSequence title, Class fragmentClass, Bundle args ) {
adapter.addTab( title, fragmentClass, args );
}
My fragment TabFragmentMeasurement.class
public class TabFragmentMeasurement extends Fragment {
....... // Class' attributes
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
setHasOptionsMenu(true);
TextView txt = new TextView( inflater.getContext() );
....... // Change TextView's attributes
return txt;
}
#Override
public void onCreateOptionsMenu(Menu menu,MenuInflater inflater)
{
inflater.inflate(R.menu.measurement, menu);
super.onCreateOptionsMenu(menu,inflater);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle presses on the action bar items
switch (item.getItemId()) {
case R.id.item_add_measurement:{
// Add a measurement
}
default:
return super.onOptionsItemSelected(item);
}
}
}
XML menu file measurement.xml
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:id="#+id/action_settings"
android:orderInCategory="100"
android:showAsAction="never"
android:title="#string/action_settings"/>
<item
android:id="#+id/item_add_measurement"
android:icon="#android:drawable/ic_menu_add"
android:orderInCategory="1"
android:showAsAction="ifRoom"
android:title="#string/item_add_measurement"/>
</menu>
Why don't you extends SherlockFragment in the fragment classes??
Keep in mind that every context you pass like "this" should be followed by :
this.getSherlockActivity().

Android MenuItem.getItemId returns integer values

I have a problem in my Android project trying to make a options menu.
When I debug/execute my app and click over the menu-button, ALWAYS R.id.btnInfo attribute returns an integer, not the menu item id (btnInfo).
Here is the code:
Menu declaration:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="#+id/btnInfo"
android:title="#string/btnInfo"
android:icon="#drawable/ic_info" />
</menu>
Loading menu:
/**
* Options Menu Inflater Event
*/
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.options, menu);
return true;
}
Click Event:
/**
* Click on Options Menu Button
*/
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.btnInfo:
// To-do:
return true;
default:
return super.onOptionsItemSelected(item);
}
}
This is the correct behaviour.
Check the R.java file, for each item you give an ID, it generates an integer ID to refer too.
Example:
public static final class menu {
public static final int option1=0x7f0a0000;
public static final int option2=0x7f0a0001;
public static final int option3=0x7f0a0002;
}

Categories

Resources