I'm creating a universal app compatible with Froyo upwards, so I'm using the brilliant ActionBarSherlock. I wish to create submenu pulldowns from Action Items in the ActionBar that includes icons and text in the rows. There are a few threads that ask similar questions but I got no where with trying to implement them. I've tried Spinners but I need API 8 compatibility, so then I tried IcsSpinner in the Sherlock lib but Jake had advised someone else not to rely on it in case the lib changed. I tried a custom ActionProvider to mimic the ShareActionProvider but I found it too complicated:
This image shows exactly what I want but I could not get it to work with my app. My code is as follows:
public class AddDocActionProvider extends ActionProvider {
private Context mContext;
public AddDocActionProvider(Context context) {
super(context);
mContext = context;
}
#Override
public View onCreateActionView() {
LayoutInflater layoutInflater = LayoutInflater.from(mContext);
View view = layoutInflater.inflate(
R.layout.actionbar_new_doc_action_provider, null);
return view;
}
#Override
public boolean hasSubMenu() {
return true;
}
#Override
public void onPrepareSubMenu(SubMenu subMenu) {
// loop was here calling
subMenu.add(0, id, 0, "Type 1")
.setIcon(R.drawable.type_1)
.setOnMenuItemClickListener(mOnMenuItemClickListener);
// added type 2, 3, etc
}
#Override
public boolean onPerformDefaultAction() {
// This is called if the host menu item placed in the overflow menu of the
// action bar is clicked and the host activity did not handle the click.
return true;
}
My SherlockFragmentActivity had this code:
#Override
public boolean onCreateOptionsMenu(com.actionbarsherlock.view.Menu menu) {
MenuItem newDoc = menu.add(0, MENU_ADD_DOC, 0, "New Document");
newDoc.setVisible(!isPhoneShowingStorageList);
newDoc.setIcon(R.drawable.dark_content_new);
newDoc.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
mNewDocActionProvider = new AddDocActionProvider(getSupportActionBar().getThemedContext());
newDoc.setActionProvider(mNewDocActionProvider);
}
I don't see the submenu and it also crashes on froyo phones when the actionbar invalidates.
Other threads I've looked at:
How to create a custom Pulldown in the Honeycomb ActionBar?
How to add a Dropdown item on the action bar
Custom drop-down from action item (actionbarsherlock)
While this isn't necessarily an ActionBarSherlock specific issue, frankly I can't believe something this easy should be so complicated to implement in the standard Action Bar. Any help would be greatly appreciated.
UPDATE:
Using XML rather than code added the icons for me:
<item
android:id="#+id/menu_new_doc"
android:icon="#drawable/dark_content_new"
android:showAsAction="always"
android:title="New Document">
<menu>
<item
android:id="#+id/word2010"
android:icon="#drawable/doc"
android:title="Word 2010"/>
<item
android:id="#+id/excel2010"
android:icon="#drawable/excel"
android:title="Excel 2010"/>
</menu>
</item>
So in order to dynamically had the submenus, I had to do this:
MenuItem newDoc = menu.findItem(R.id.menu_new_doc);
SubMenu subMenu = newDoc.getSubMenu();
subMenu.clear();
for (/* loop */) {
MenuItem subMenuItem = subMenu.add(0, hash, 0, fileType.GetDescription());
subMenuItem.setIcon(R.drawable.doc);
}
i think you should set the icon to the newly added Item to the subMenu. Example :
public boolean onCreateOptionsMenu(Menu menu) {
SubMenu subMenu = menu.addSubMenu("Add");
subMenu.add("Add Subitem 1").setIcon(R.drawable.ic_action_add1);
subMenu.add("Add Subitem 2").setIcon(R.drawable.ic_action_add2);
MenuItem subMenu1Item = subMenu.getItem();
subMenu1Item.setIcon(R.drawable.ic_action_add);
subMenu1Item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
return super.onCreateOptionsMenu(menu);
}
Related
How to create optionmenu for Android 3.0 and higher version mobiles?
I am trying to create options menu in my Android program. I am using the following code to inflate options menu. option menu icon not showing in higher version mobiles..
public class MainScreenTab extends FragmentActivity implements
ActionBar.TabListener {
private ViewPager viewPager;
private TabsPagerAdapter mAdapter;
private ActionBar actionBar;
private String[] tabs = { "Merchants", "Personal Payee" };
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_screen_tab_layout);
//Initilization
viewPager = (ViewPager) findViewById(R.id.pager);
actionBar = getActionBar();
mAdapter = new TabsPagerAdapter(getSupportFragmentManager());
viewPager.setAdapter(mAdapter);
actionBar.setHomeButtonEnabled(false);
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
//Adding Tabs
for (String tab_name : tabs) {
actionBar.addTab(actionBar.newTab().setText(tab_name)
.setTabListener(this));
}
viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageSelected(int position) {
// on changing the page
// make respected tab selected
actionBar.setSelectedNavigationItem(position);
}
#Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
}
#Override
public void onPageScrollStateChanged(int arg0) {
}
});
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main, menu); //inflate our menu
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
// switch(item.getItemId()) {
int id = item.getItemId();
if (id == R.id.item_refresh) {
Intent i = new Intent(MainScreenTab.this,ListMerchantType.class);
startActivity(i);
return true;
}
else if (id == R.id.item_save) {
Intent i = new Intent(MainScreenTab.this,ListPayee.class);
startActivity(i);
return true;
}
return super.onOptionsItemSelected(item);
}
}
You just need to use this Reflection method to force your icon in the ActionBar
public static void forceOverFlowIconInActionBar(Activity mActivity)
{
try
{
ViewConfiguration config = ViewConfiguration.get(mActivity);
Field menuKeyField = ViewConfiguration.class.getDeclaredField("sHasPermanentMenuKey");
if(menuKeyField != null)
{
menuKeyField.setAccessible(true);
menuKeyField.setBoolean(config, false);
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
Try this one. import java.lang.reflect.Field; And on your onCreateOptionsMenu() method just simply add:
if (menu.getClass().getSimpleName().equals("MenuBuilder")) {
try {
Field field = menu.getClass().getDeclaredField("mOptionalIconsVisible");
field.setAccessible(true);
field.setBoolean(menu, true);
} catch (Exception ignored) {
ignored.printStackTrace();
}
}
and don't forget to add this to your xml menu android:icon="#drawable/blah_blah" . Hope it helps. And don't forget to up-vote if it is helpful.
Menus: Generally a list of commands or facilities displayed on screen. It is a common user interface for the user. If you want to provide a familiar and consistent user experience you should use Menus in your activity. It is beginning with android 3.0(Api level 11). So design and user experience my change for device to device that is depends on the Menu apis.
There mainly there menus in the android. Those are Options menu, Context menu, Popup Menu.
Options menu:
Options menu is a collection of menu items for an activity. The place where you locate icons that is very impact to the app. Such menu items are search, settings, compose email.
If you are developing the options menu for Android 2.3 and lower user can reveal the options menu by pressing menu button. On the 3.0 and higher the options menu items as a combination of action bar items. Beginning with Android 3.0, the Menu button is deprecated (some devices don't have one), so you should migrate toward using the action bar to provide access to actions and other options.
Creating Options Menu in android
Simply options menu is where you should you include options and other actions what are relevant to activity. The item in the options menu is depends on the version you are using.
If it is below 3.0 that comes when you press the menu buttons. If it is higher that will comes to the top of the screen. Means that will include with the action bar screen.
You can declare items for the options menu from either your Activity subclass or a Fragment subclass. At one time if you declare both the items in the activity then that will appear one followed another. You can also reorder the menu items in the android:orderInCategory attribute in each you need to move.
To specify a menu item in the activity first you need to override one method. That method is onCreateOptionsMenu() . This mehtod fragments provide their own onCreateOptionsMenu() callback.
Example:
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.game_menu, menu);
return true;
}
We can perform add and retrieve options in the menu item api by using add() and findItem().
Handling click events in onCreateOptionsMenu():
If you want to provide a click event on the menu items the system calls onOptionsItemSelected. In that method you can identify which item you are selected by using item.getItemId(). which returns the unique ID for the menu item (defined by the android:id attribute in the menu resource or with an integer given to the add() method). You it is matched you can perform your action whatever you want.
Example:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle item selection
switch (item.getItemId()) {
case R.id.new_game:
newGame();
return true;
case R.id.help:
showHelp();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
When you successfully handle the menu item that will returns true. If not handle that item that will you should call the superclass implementation of onOptionsItemSelected().
Changing menu items at runtime:
When you call onCreateOptionsMenu() that is displaying simple onCreateOptionsMenu(). you can not change the items in the run time. If you want to change the items in the run time you need to call onPrepareOptionsMenu() method. This method passes you the Menu object as it currently exists so you can modify it, such as add, remove, or disable items.
Example Project:
Open your eclipse and create one project name called OptionsMenu.
In that open you menu folder in the resource folder. In the main.xml file add how many items you want. You can get main.xml file below.
Main.xml
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:id="#+id/menu_settings" android:orderInCategory="100"
android:showAsAction="never" android:title="#string/menu_settings"/>
<item android:id="#+id/item1" android:title="Tutorial 1"></item>
<item android:id="#+id/item2" android:title="Tutorial 2"></item>
<item android:id="#+id/item3" android:title="Tutorial 3"></item>
<item android:id="#+id/item4" android:title="Tutorial 4"></item>
<item android:id="#+id/item5" android:title="Tutorial 5"></item>
</menu>
Here i used #string/menu_settings so you can add that item in the strings.xml file.
strings.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">OptionsMenu</string>
<string name="hello_world">Hello world!</string>
<string name="menu_settings">Settings</string>
</resources>
Once that is done open your main activity. In that write the onCreateOptionsMenu method for adding the menu item to the activity. Once that is done if you want to give click events you write onOptionsItemSelected. You can get the complete code below.
MainActivity
package com.tutorialindustry.optionsmenu;
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;
public class MainActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.item1:
Toast.makeText(this, "Tutorial 1 Selected", Toast.LENGTH_SHORT).show();
return true;
case R.id.item2:
Toast.makeText(this, "Tutorial 2 Selected", Toast.LENGTH_SHORT).show();
return true;
case R.id.item3:
Toast.makeText(this, "Tutorial 3 Selected", Toast.LENGTH_SHORT).show();
return true;
case R.id.item4:
Toast.makeText(this, "Tutorial 4 Selected", Toast.LENGTH_SHORT).show();
return true;
case R.id.item5:
Toast.makeText(this, "Tutorial 5 Selected", Toast.LENGTH_SHORT).show();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
}
Once that is done run you project that you can get the below output. In this way we can perform options menu in the android.
I'm a Java programmer with experience. I started working on a small Android project and i got soooo frustrated by how much Android has complicated programming just to be more flexible.
Exactly, the problem i have is as follows: i have a menu item that i need to use in several menus inside mu app. Is there a way to create a menu item object (possible associate some function to it) and just pass it around so any activity can add it to it's own contex menu?
I have tried this:
Created a "res.menu.mymenu.xml" file that contains a menu item with the same id as menu item from another "res.menu.mymenu2.xml" file. Then i have tried this:
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
MenuInflater inflater = getMenuInflater();
inflater.inflate(getMenuToInflate(), menu);
menu.add(0, R.id.mnhidefrom, 0, ((MenuItem)findViewById(R.id.mnhidefrom)).getTitle());
HideMenuAction.prepareAndGetHideMeMenuItem(menu, menuInfo); //creating an intent for "hide" menu item that will hold some data needed when user clicks the menu item.
}
But no luck... I got "null pointer exception" on "menu.add" line...
Is there a normal, object oriented way, to create a menu item that will know what it should do regardless of anything outside (like,say, menu it belongs to) and just pass it around like any other object and add it to any menu i like (just like i can do with Swing menu and JMenuItems)?
Ahmad has half the story. This will give you a base of menu options that are always available. The way to add menu options specific to each extending activity is to write a Fragment for it. The fragment will included in the activity layout, but you can make it take up no room or use it for padding. When a Fragment implements onCreateOptionsMenu, the choices it adds are merged with the ones that the Activity created.
Read everything to do with the options menu in this guide for more details:
http://developer.android.com/guide/topics/ui/menus.html
Is there a normal, object oriented way
Yes there is. It's called inheritance!
Create a base Activityin which you inflate the OptionsMenu once and extend this Activity for all your Activities.
public class BaseActivity extends Activity {
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.blabla:
// do something
break;
case R.id.blablab:
// do something
break;
}
return true;
}
}
Now you can do this:
public class MainActivity extends BaseActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
return true;
}
}
I used a BaseActivity as Ahmad described. It works fine.
Now I want to show a special menu item in one specific Activity (which extends the BaseActivity).
#Override
public boolean onOptionsItemSelected(android.view.MenuItem item) {
switch (item.getItemId()) {
case 0:
Intent intent = new Intent(this, BlaActivity.class);
startActivity(intent);
return true;
default:
return super.onOptionsItemSelected(item);
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuItem item = menu.add(Menu.NONE, 0, 0, "Edit");
item.setIcon(R.drawable.content_edit);
return super.onCreateOptionsMenu(menu);
}
This works as I expected, but I can't get the new inserted menuitem to get in the first position.
I need it to be in first position, so it is displayed directly in the ActionBar and the user sees that there is a new option without clicking on the options button.
Edit: I just found the solution myself.
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuItem item = menu.add(Menu.NONE, 0, 0, "Bearbeiten");
item.setIcon(R.drawable.content_edit);
if (android.os.Build.VERSION.SDK_INT >= 11) {
item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS); //<-----
}
return super.onCreateOptionsMenu(menu);
}
I have five action menu items in the action bar, which I'm using action bar sherlock library as follows :
In onCreateOptionsMenu(), i used the following code :
menu.add(0,1,0 "Settings")
.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
menu.add(0,2,0 "Favorites")
.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
menu.add(0,3,0 "List")
.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
menu.add(0,4,0 "Upload")
.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
menu.add(0,5,0 "Search")
.setActionView(R.layout.search_layout)
.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS | MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW);
Now my Problem is Search Edit text (which is in red color) appears like this:
I want to make it to a full view in the action bar, like this :
This question is a bit old but I'll try to answer it anyway. I hope someone will find it useful.
Here is what I have done:
Create a custom SearchView class that extends SearchView. It defines 2 events: one fired when the search view expands and the other when it collapses.
public class EnglishVerbSearchView extends SearchView {
OnSearchViewCollapsedEventListener mSearchViewCollapsedEventListener;
OnSearchViewExpandedEventListener mOnSearchViewExpandedEventListener;
public EnglishVerbSearchView(Context context) {
super(context);
}
#Override
public void onActionViewCollapsed() {
if (mSearchViewCollapsedEventListener != null)
mSearchViewCollapsedEventListener.onSearchViewCollapsed();
super.onActionViewCollapsed();
}
#Override
public void onActionViewExpanded() {
if (mOnSearchViewExpandedEventListener != null)
mOnSearchViewExpandedEventListener.onSearchViewExpanded();
super.onActionViewExpanded();
}
public interface OnSearchViewCollapsedEventListener {
public void onSearchViewCollapsed();
}
public interface OnSearchViewExpandedEventListener {
public void onSearchViewExpanded();
}
public void setOnSearchViewCollapsedEventListener(OnSearchViewCollapsedEventListener eventListener) {
mSearchViewCollapsedEventListener = eventListener;
}
public void setOnSearchViewExpandedEventListener(OnSearchViewExpandedEventListener eventListener) {
mOnSearchViewExpandedEventListener = eventListener;
}
}
In my activity, I did the following:
- Created a private field to store the reference to the menu.
- Defined the events for collapsing and expanding the search view where I hide and show other actions by using the reference to the menu.
public class DictionaryActivity extends ActionBarActivity {
private Menu mMenu;
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.dictionary, menu);
MenuItem searchItem = menu.findItem(R.id.action_search);
EnglishVerbSearchView searchView = (EnglishVerbSearchView) MenuItemCompat.getActionView(searchItem);
searchView.setOnSearchViewCollapsedEventListener(listenerCollapse);
searchView.setOnSearchViewExpandedEventListener(listenerExpand);
mMenu = menu;
return super.onCreateOptionsMenu(menu);
}
final private OnSearchViewCollapsedEventListener listenerCollapse = new OnSearchViewCollapsedEventListener() {
#Override
public void onSearchViewCollapsed() {
// show other actions
MenuItem favouriteItem = mMenu.findItem(R.id.action_favourite);
MenuItem playItem = mMenu.findItem(R.id.action_play);
favouriteItem.setVisible(true);
playItem.setVisible(true);
// I'm doing my actual search here
}
};
final private OnSearchViewExpandedEventListener listenerExpand = new OnSearchViewExpandedEventListener() {
#Override
public void onSearchViewExpanded() {
// hide other actions
MenuItem favouriteItem = mMenu.findItem(R.id.action_favourite);
MenuItem playItem = mMenu.findItem(R.id.action_play);
favouriteItem.setVisible(false);
playItem.setVisible(false);
}
};
}
In the menu.xml file, I used the custom search view:
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:yourapp="http://schemas.android.com/apk/res-auto" >
<item android:id="#+id/action_search"
android:title="#string/action_search"
android:icon="#drawable/action_search"
yourapp:showAsAction="always|collapseActionView"
yourapp:actionViewClass="com.xxx.EnglishVerbSearchView" />
</menu>
I hope it's all that's needed as it's just an extract from my full code of the activity. Let me know if there's anything missing.
As per comment from arne.jans:
It seems to be enough to do MenuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); to make room for the SearchView. The advantage would be: the other menu-items go into the overflow menu and are still accessible, even with the opened SearchView.
I'm trying to implement the contextual action bar in my app. I'm extending a ListFragment and I have a custom ArrayAdapter and list item xml defined. Clicking on items works fine and the background color changes on the list item. Where I'm running into trouble is when selecting multiple items. The contextual action bar comes up and I can tell I'm actually selecting items when I touch them because I'm having it log which items are selected, but the background highlight color on the list item does not change! It seems like some other people were running into this problem when using the Fragments API as well and they had come up with a sort-of hack to get it to work properly. However, I was wondering if anyone has a definitive answer as to why my list doesn't show selected items.
For good measure, here's my code:
ListView list = getListView();
list.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
list.setSelector(R.drawable.list_selector);
// configure contextual action bar
list.setMultiChoiceModeListener(new AbsListView.MultiChoiceModeListener() {
#Override
public void onItemCheckedStateChanged(ActionMode actionMode, int position, long id, boolean b) {
Log.i("debug", "item " + position + " changed state");
}
#Override
public boolean onCreateActionMode(ActionMode actionMode, Menu menu) {
MenuInflater inflater = actionMode.getMenuInflater();
inflater.inflate(R.menu.context_menu, menu);
return true;
}
#Override
public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) {
return false;
}
#Override
public boolean onActionItemClicked(ActionMode actionMode, MenuItem item) {
switch (item.getItemId()) {
case R.id.delete:
Log.i("debug", "delete stuff");
return true;
default:
return false;
}
}
#Override
public void onDestroyActionMode(ActionMode actionMode) {
}
});
I provide my custom list item view with a background selector.
<selector xmlns:android="http://schemas.android.com/apk/res/android"
android:exitFadeDuration="#android:integer/config_mediumAnimTime">
<item android:state_activated="true" android:drawable="#drawable/number_bg_pressed" />
<item android:drawable="#android:color/transparent" />
I refer to APIdemos View/List/List16 example.
I use android.R.layout.simple_list_item_activated_1 for layout when I set up SimpleCursorAdapter. Custom theme may be a better solution. In my case I have a static method to retrieve the layout depending on android api version.
I need to change the color of a menuItem in an ActionBar (that list that appear when the user press a menuItem in my Action Bar).
Which element of the android:style/Widget.Holo.Light.ActionBar I have to change?
Which style I'll have to create to change the android:style/Widget.Holo.Light.ActionBar?
I am not sure you can do that for a particular menuItem, but you can have a look on a more complete blog post about Styling the ActionBar : Part 1 and Part 2
Edit : after looking at the articles another time, I think what you want to do is not possible. The best thing is to create an icon with the appropriate color of your menuitem and to change it when you want.
menu.xml :
<item android:id="#+id/my_menu_item"
android:icon="#drawable/my_menu_item_icon_color1"
android:title="#string/my_menu_item"
android:showAsAction="ifRoom" />
in your activity :
/**
* Create default menu and keep it in a private var
*/
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main_menu, menu);
mMenuActionBar = menu;
return true;
}
/**
* Method changing your item to second icon
*/
private void updateActionBar() {
if (mMenuActionBar != null) {
MenuItem menuItem = mMenuActionBar.findItem(R.id.my_menu_item);
if (menuItem != null) {
menuItem.setIcon(#drawable/my_menu_item_icon_color2);
invalidateOptionsMenu();
}
}
}