I'm trying to create this kind of list menu but with no success:
I would like to use the Android menu button or to press an arrow with "open" or "close" text.
That menu will display a list of options :
[Icon] + Open/close
[Icon] + Take a picture
[Icon] + Import pictures from the gallerie
[Icon] + Delete picture alrealy sent
But, I've got this kind of result, a menu as block options:
I'm using this code from Android developer website :
XML File (/menu/gallerie_menu.xml) :
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="#+id/open_or_close"
android:icon="#drawable/ic_open"
android:title="#string/open"
android:showAsAction="ifRoom"/>
<item android:id="#+id/take_pic"
android:icon="#drawable/ic_camera"
android:title="#string/take_picture" />
<item android:id="#+id/import_pic"
android:icon="#drawable/ic_import"
android:title="#string/import_picture" />
<item android:id="#+id/delete"
android:icon="#drawable/ic_delete"
android:title="#string/delete_picture" />
</menu>
Java code:
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.gallerie_menu, menu);
return true;
}
Could someone advise me or suggest something to me?
The only option I can suggest is not a particularly straightforward one.
If inside your activity you declare a PopupWindow variable:
private PopupWindow myMenu;
Then in the OnCreate of that activity setup your menu window inflate the layout xml file that is the way you want you menu to look and add eventhandlers as necissary:
View v = getLayoutInflater().inflate(R.layout.test_menu, null, false);
Button b = (Button)v.findViewById(R.id.myFirstMenuOption);
b.setOnClickListener(new OnClickListener(){
#Override
public void onClick(View v) {
//do something....
}
});//repeat for rest off menu buttons.
myMenu = new PopupWindow(v, 0, 0, false);
myMenu.setWidth(LayoutParams.MATCH_PARENT);
myMenu.setHeight(LayoutParams.WRAP_CONTENT);
Then override the onKeyDown method of your activity to show the menu in response to the button press:
#Override
public boolean onKeyDown(int keyCode, KeyEvent event)
{
if (keyCode == KeyEvent.KEYCODE_MENU)
{
if (myMenu.isShowing())
{
myMenu.dismiss();
}
else
{
ScrollView sv = (ScrollView)findViewById(R.id.mainLayout);
myMenu.showAtLocation(sv, android.view.Gravity.BOTTOM | android.view.Gravity.LEFT, 0, 0);
}
return true; //swallow the event
}
return super.onKeyDown(keyCode, event);
}
The ScrollView here being the topmost view in my activity's layout xml.
There are various options from here on in, for example to code a reusable PopupWindow class of your own, but I leave that to you if this option is what you decide to go with.
Hope this helps you.
Related
I have a TextView where a user is able to select a text. By default the following options appear: "Copy", "Share" and "Select All".
I need to override them with custom options. But I can't find how to do that. I went through the documentation and this nice article but no lack. The article explains how to extend the menu when a user presses three-dots-button which is not what I need.
Question: How can I override default "Copy", "Share" and "Select All" options in text section menu?
Here is how my view looks like:
<TextView
android:id="#+id/transcript"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scrollbars="vertical" />
And in java code I have:
transcript.setTextIsSelectable(true);
transcript.setFocusable(true);
transcript.setFocusableInTouchMode(true);
You can use TextView.setCustomSelectionActionModeCallback() to do this.
Documentation: https://developer.android.com/reference/android/widget/TextView.html#setCustomSelectionActionModeCallback(android.view.ActionMode.Callback)
I put together a very simple app to demonstrate how to use this feature.
MainActivity.java
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView text = (TextView) findViewById(R.id.text);
CustomActionModeCallback callback = new CustomActionModeCallback(this);
text.setCustomSelectionActionModeCallback(callback);
}
}
activity_main.xml
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/text"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="16dp"
android:text="#string/lorem_ipsum"
android:textIsSelectable="true"/>
</FrameLayout>
CustomActionModeCallback.java
public class CustomActionModeCallback implements ActionMode.Callback {
private final Context context;
public CustomActionModeCallback(Context context) {
this.context = context;
}
#Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
menu.clear();
mode.getMenuInflater().inflate(R.menu.menu_custom, menu);
return true;
}
#Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false;
}
#Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
if (item.getItemId() == R.id.custom_one) {
Toast.makeText(context, "One!", Toast.LENGTH_SHORT).show();
mode.finish();
return true;
}
else if (item.getItemId() == R.id.custom_two) {
Toast.makeText(context, "Two!", Toast.LENGTH_SHORT).show();
mode.finish();
return true;
}
else if (item.getItemId() == R.id.custom_three) {
Toast.makeText(context, "Three!", Toast.LENGTH_SHORT).show();
mode.finish();
return true;
}
return false;
}
#Override
public void onDestroyActionMode(ActionMode mode) {
}
}
menu_custom.xml
<menu
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="#+id/custom_one"
android:title="One"
app:showAsAction="never"/>
<item
android:id="#+id/custom_two"
android:title="Two"
app:showAsAction="never"/>
<item
android:id="#+id/custom_three"
android:title="Three"
app:showAsAction="never"/>
</menu>
Nothing much to comment on in MainActivity or either xml file. All the magic happens in CustomActionModeCallback.
Both onCreateActionMode() and onPrepareActionMode() can be used to add your custom menu items to the menu. If you use onCreateActionMode(), the system will add some extra options into an overflow menu, like this:
If you use onPrepareActionMode(), the extra items won't be added.
Note that you must return true from onCreateActionMode() no matter what (returning false causes the menu to not be displayed), but you only have to return true from onPrepareActionMode() if you've actually modified the menu.
You can handle the user's clicks on your custom items inside onActionItemClicked(). In my example, I simply show a Toast and then close the contextual menu (using ActionMode.finish()). In this method, you should return true only on menu items that you handle yourself; returning false allows the system default action to happen (such as if you want to give the user the option to select all text).
Finally, onDestroyActionMode() is called when the menu is closed. Perhaps you have some use for this; I did not.
I am trying to animate between the visibility mode for a menu.
By default all menu items are hidden but when the user clicks on the edit button i want to show all the items with an animation.
I have achieved the first part of changing the visibility of the menu items and that works fine but the animation part crashes the app.
Here is my code.
When user clicks on edit this is called.By default edit_mode is false.
if (!edit_mode) {
edit_mode = true;
supportInvalidateOptionsMenu();
}
This is the menu code.
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_add__custom, menu);
return true;
}
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
MenuItem photo = menu.findItem(R.id.photo);
photo.setVisible(edit_mode);
if (edit_mode)
photo.getActionView().animate().alpha(1.0f);
MenuItem date = menu.findItem(R.id.date);
date.setVisible(edit_mode);
if (edit_mode)
date.getActionView().animate().alpha(1.0f);
MenuItem done = menu.findItem(R.id.done);
done.setVisible(edit_mode);
if (edit_mode)
done.getActionView().animate().alpha(1.0f);
return edit_mode;
}
menu.xml
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<item
android:id="#+id/date"
android:icon="#drawable/ic_event_white_24dp"
android:orderInCategory="200"
android:title="Date"
app:showAsAction="ifRoom" />
<item
android:id="#+id/done"
android:icon="#drawable/ic_done_white_24dp"
android:orderInCategory="300"
android:title="Done"
app:showAsAction="ifRoom" />
<item
android:id="#+id/photo"
android:icon="#drawable/ic_photo_white_24dp"
android:orderInCategory="100"
android:title="Done"
app:showAsAction="ifRoom" />
I sure that crash that you are having is there because of NullException thrown by getActionView(). First of all to animate that way you have set the actionView first during onCreateOptionMenu(). That way when you get the actionView in onPrepareOptionsMenu it wont crash because of that and then you can animate it. The onPrepareOptionsMenu executes when you press the menu button so your logic to animate it that time is correct.
If its just the text you want to show in menu item, it should go like this,
final MenuItem photo;
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_my_report, menu);
photo = menu.findItem(R.id.action1);
TextView textView = new TextView(this);
textView.setText("I am menu item");
photo.setActionView(textView);
return true;
}
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
if(someCondition)
{
photo.getActionView().animate().alpha(1.0f);
}
return super.onCreateOptionsMenu(menu);
}
In case you want to have the a complex and customise text you can set it using the layoutInflator service. This could go in your onCreate,
LayoutInflater inflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
ImageView view = (ImageView)inflater.inflate(R.layout.some_view, null);
Animation rotation = AnimationUtils.loadAnimation(this, R.anim.fade);
and onCreateOptionMenu,
view.startAnimation(rotation);
photo.setActionView(view);
Its just to get you an idea what needed to be done, you can play around with this and can suit your need.
Hi so for my needs i cannot use SearchView because i am filtering an array list that contains some custom object plus this AutoCompleteTextView is embedded into the toolbar as a menu item
<item
android:id="#+id/searchFoodMenuItem"
android:title="#string/generic.search"
app:actionLayout="#layout/view_search_food_auto_complete"
android:orderInCategory="1"
android:icon="#drawable/ic_search_white_48dp"
app:showAsAction="ifRoom|collapseActionView"
/>
I wish to mimic the behaviour of searchview in these cases:
Clicking on the icon puts the auto complete text view in focus and brings up the key board (I have kind of achieved this but i have a small issue that i need help with)
While the auto complete text view is in focus, clicking anywhere else on the screen that is not the keyboard will remove the focus of the auto complete text view rather than passing the touch to the view that was pressed.
Some code
So i wrote my own extension of the AutoCompleteTextView.
Here is some key snippets
The part below simply closes / opens the keyboard when the focus of the view has changed. This also includes clicking on it and pressing back on the soft keyboard.
#Override
protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
super.onFocusChanged(focused, direction, previouslyFocusedRect);
InputMethodManager inputMethodManager = (InputMethodManager) getContext()
.getSystemService(Context.INPUT_METHOD_SERVICE);
if (focused) {
inputMethodManager.showSoftInput(this, 0);
} else {
setFocusableInTouchMode(false);
inputMethodManager.hideSoftInputFromWindow(getWindowToken(), 0);
}
}
#Override
public boolean performClick() {
setFocusableInTouchMode(true);
requestFocus();
return super.performClick();
}
#Override
public boolean onKeyPreIme(int keyCode, KeyEvent event) {
if (event.getKeyCode() == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_UP) {
clearFocus();
}
return false;
}
Below is the code which puts the view into focus when the menu item is expanded
MenuItemCompat.setOnActionExpandListener(mSearchFoodMenuItem, new MenuItemCompat.OnActionExpandListener() {
#Override
public boolean onMenuItemActionExpand(MenuItem item) {
mSearchFoodInputField.post(new Runnable() {
#Override
public void run() {
DebugUtils.Log("onMenuItemActionExpand");
mSearchFoodInputField.requestFocus();
}
});
return true;
}
#Override
public boolean onMenuItemActionCollapse(MenuItem item) {
return true;
}
});
The above works the first time, i.e. if i click on the menu item, the auto complete text view becomes focused and the key board appears. All is well, but if i collapse this menu item and do it again, it no longer becomes focused and i am not sure why.
More reasons I am not using SearchView
The main reason I do not want to use it is because I want to display search suggestions based on my array list of objects. My understanding of the API tells me that search view can only do this on a database Cursor (which I am not using)
Search view code
The menu
<?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_search"
android:title="#string/generic.search"
android:icon="#drawable/ic_search_white_48dp"
app:showAsAction="ifRoom|collapseActionView"
android:iconifiedByDefault="true"
app:actionViewClass="android.support.v7.widget.SearchView" />
</menu>
In onCreateOptionsMenu
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.piece_discover_menu, menu);
mSearchMenuItem = menu.findItem(R.id.action_search);
mSearchView = (SearchView) MenuItemCompat.getActionView(mSearchMenuItem);
mSearchView.setOnQueryTextListener(this);
mSearchView.setOnSuggestionListener(this);
mSearchView.setSuggestionsAdapter(mFoodSearchAdapter);
}
Below is what i tried
I made a searchable config
Note i tried with and without completetionThreshold
<?xml version="1.0" encoding="utf-8"?>
<searchable xmlns:android="http://schemas.android.com/apk/res/android"
android:hint=“#string/search_hint”
android:searchSuggestThreshold=“1”
android:completionThreshold=“1”
</searchable>
Me applying the search config
Note this was declared between the application tags
<meta-data android:name="android.app.searchable"
android:resource="#xml/searchable" />
Me adding the search manager
SearchManager searchManager =
(SearchManager) getActivity().getSystemService(Context.SEARCH_SERVICE);
mSearchView.setSearchableInfo(
searchManager.getSearchableInfo(getActivity().getComponentName()));
Thanks to pskink , I used a search view instead. To get suggestions like the AutoCompleteTextView i used a cursorAdapter. However if like me you had an array list of some Java object, you need to convert it to a Cursor as follows.
public static final String[] COLUMNS = new String[]{"_id","foodName","foodReference"};
public static final int ID_INDEX = 0, FOOD_NAME_INDEX = 1, FOOD_REFERENCE_INDEX = 2;
private MatrixCursor convertToCursor (ArrayList<Food> foods){
MatrixCursor cursor = new MatrixCursor(COLUMNS);
for(Food food : foods){
String[]row = new String[COLUMNS.length];
row[ID_INDEX] = Integer.toString(mFoods.indexOf(food));
row[FOOD_NAME_INDEX] = food.getName();
row[FOOD_REFERENCE_INDEX] = food.getReferenceNumber();
cursor.addRow(row);
}
return cursor;
}
I am trying to enable the user to stops and starts service which I am implementing from the Menu where the text is will be changed when he clicks it so I want to add ToggleButton as option in the menu tool but nothing is being display in my case now. How can I fix it?
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<ToggleButton
android:id="#+id/toggle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textOff="Off"
android:textOn="On" />
</menu>
MainActivity:
public class MainActivity extends ActionBarActivity {
ToggleButton tButton;
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main_menu, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.toggle:
tButton = (ToggleButton) findViewById(R.id.toggle);
tButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (((ToggleButton) v).isChecked()) {
Intent i = new Intent(MainActivity.this,
TrackingService.class);
startService(i);
System.out.println("test is checked, start service");
} else {
// Stop the service when the Menu button clicks.
Intent i = new Intent(MainActivity.this,
TrackingService.class);
stopService(i);
System.out.println("test is NOT checked, stop service");
}
}
});
return true;
default:
return false;
}
}
}
Edit:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.checkable_menu:
if (isChecked = !item.isChecked()) {
item.setChecked(isChecked);
Intent i = new Intent(this, TrackingService.class);
startService(i);
System.out.println("test if onOptionsItemSelected");
} else {
Intent i = new Intent(this, TrackingService.class);
stopService(i);
System.out.println("test else onOptionsItemSelected");
}
return true;
default:
System.out
.println("test default onOptionsItemSelected was invoked.");
return false;
}
}
It is easy. Rather you will have your toggle button on Toolbar.
<item
android:id="#+id/show_secure"
android:enabled="true"
android:title=""
android:visible="true"
app:actionLayout="#layout/show_protected_switch"
app:showAsAction="ifRoom" />
And this is your show_protected_switch.xml layout.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ToggleButton
android:id="#+id/switch_show_protected"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/switch_ptotected_btn_selector"
android:textOff=""
android:textOn=""/>
</RelativeLayout>
And in code:
ToggleButton mSwitchShowSecure;
mSwitchShowSecure = (ToggleButton) menu.findItem(R.id.show_secure).getActionView().findViewById(R.id.switch_show_protected);
mSwitchShowSecure.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
if(b){
//Your code when checked
} else {
//Your code when unchecked
}Y
}
});
Output!
It is rather big but you can adjust its size, obviously
I know its very a long time to post an answer, but it may help someone :)
I followed this link and update some of the implemented solution as the app was crashed before these modifications
And below is the full solution:
1- Create a new xml file under layout folder and name it switch_layout.xml and put the below:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="match_parent"
android:orientation="horizontal" >
<Switch
android:id="#+id/switchAB"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true" />
</RelativeLayout>
2- Add the below menu item in the main.xml file under menu folder:
<item
android:id="#+id/switchId"
android:title=""
app:actionLayout="#layout/switch_layout"
app:showAsAction="always" />
3- Go to your activity and below is a full implementation for onCreateOptionsMenu method:
#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);
MenuItem item = (MenuItem) menu.findItem(R.id.switchId);
item.setActionView(R.layout.switch_layout);
Switch switchAB = item
.getActionView().findViewById(R.id.switchAB);
switchAB.setChecked(false);
switchAB.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
if (isChecked) {
Toast.makeText(getApplication(), "ON", Toast.LENGTH_SHORT)
.show();
} else {
Toast.makeText(getApplication(), "OFF", Toast.LENGTH_SHORT)
.show();
}
}
});
return true;
}
As mentioned above, you can't add toggle button to the menu. You can use the android:checkable property in your menu item to handle the two states.
Something like:
Menu:
<item
android:id="#+id/checkable_menu"
android:checkable="true"
android:title="#string/checkable" />
Activity:
private boolean isChecked = false;
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
MenuItem checkable = menu.findItem(R.id.checkable_menu);
checkable.setChecked(isChecked);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.checkable_menu:
isChecked = !item.isChecked();
item.setChecked(isChecked);
return true;
default:
return false;
}
}
PS: Copied the code from here.
Or you can just update your item icon on click event to show the two states with item.setIcon(yourDrawable));
You cannot put any widget in <menu> and expect it to work. What you can put there is documented here and it's basically limited to menu <item> and <group>. No buttons, toggles and other widgets are supported. If that would be sufficient you can use android:checkable on the <item> or use old-skool approach and alter menu item depending on the state (if service is on, then your item should read turn service off and vice versa).
In the menu xml you add items not widgets (no buttons/textviews etc)
You simply specify an ID and an ICON for the item, then inflate them in your activities onCreateOptionsMenu() method.
then there is a method called onOptionsItemSelected(MenuItem item) check items id against the ids your expecting.
If its equal to your toggle service option determine service state and alter, if you want to have a toggle button function you can use item.setIcon(drawable) here.
Menu resources are distinct from conventional layouts; you cannot simply add widgets into them and expect them to work. The only elements allowed inside a menu resource is <item> or <group>.
Using a custom layout inside a menu isn't possible, I'm afraid. You may instead want to replace the entire menu with a PopupWindow, and supply your layouts there instead.
You may want to consider two alternatives:
Using a conventional menu entry as a toggle, or
Placing the ToggleButton immediately inside the Actionbar/Toolbar, instead of inside the menu.
so I am trying to get my menu item, that is show on the action bar to behave like a checkable menu option. The firs part works, meaning it is checkable and when I press it, and set in code the setChecked(true) it works. But what does not work is the visual part. There is no change in how a menu item looks on the action bar in checked and unchecked states? I tried using invalidateOptionsMenu() but that does not do the job, and not only that, with that line in my code I can't get out of the checked state?!?
What happens is that invalidate OptionsMenu() seams to unset the checked state and I end up 'looping', or on every press of that menu item I keep going to the unchecked part of the code where it gets checked and with invalidate it gets unchecked I guess...
Here is the code from my XML file for menu:
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="#+id/lenslist_menu_add"
android:showAsAction="always"
android:title="#string/add"/>
<item android:id="#+id/lenslist_menu_delete"
android:showAsAction="always"
android:checkable="true"
android:title="#string/delete"/>
</menu>
And here is the java code:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// TODO Auto-generated method stub
switch (item.getItemId()) {
case R.id.lenslist_menu_add:
return true;
case R.id.lenslist_menu_delete:
if (item.isChecked() == true) {
item.setChecked(false);
deleteMode = false;
lensAdapter.setDeleteMode(false);
} else {
item.setChecked(true);
deleteMode = true;
lensAdapter.setDeleteMode(true);
}
lensAdapter.notifyDataSetChanged();
return true;
}
return super.onOptionsItemSelected(item);
}
Thanks!
Checkable items appear only in submenus or context menus.
You are using them as main menu items, hence it will not work.
SOURCE: Download the API DEMOS, and open the file ApiDemos/res/menu/checkable.xml, you'll see it as a comment on line 13. I don't know why they don't mention this in the Developer Documentation
reference with comment.:
http://alvinalexander.com/java/jwarehouse/android-examples/platforms/android-2/samples/ApiDemos/res/menu/checkable.xml.shtml
Or just do it yourself
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
menu.findItem(R.id.item1).setIcon(menu_checked?R.drawable.menu_ico_checked:R.drawable.menu_ico_unchecked);
return super.onPrepareOptionsMenu(menu);
}
and in onOptionsItemSelected do:
....
menu_checked=!menu_checked;
invalidateOptionsMenu();
The best solution is to set the actionLayout of the <Item> to a CheckBox. This solution gives you a native-looking checkbox (with material animations etc), with a font that matches the other items, and it works both as an action and in the submenu.
Create a new layout called action_checkbox.html:
<?xml version="1.0" encoding="utf-8"?>
<CheckBox xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingStart="8dp"
android:paddingEnd="8dp"
android:checked="false"
android:textAppearance="#android:style/TextAppearance.DeviceDefault.Widget.ActionBar.Menu"
android:id="#+id/action_item_checkbox"
/>
Set your <Item> like this. Note that you need the Checkable and Checked still in case it is shown in a sub-menu (in which case the actionLayout is ignored.
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" tools:context=".MainActivity">
<item android:id="#+id/menu_action_logging"
android:title="#string/action_logging"
android:orderInCategory="100"
android:showAsAction="always"
android:checkable="true"
android:checked="false"
android:actionLayout="#layout/action_checkbox"
/>
</menu>
In your code, when the menu is created we need to a) set the title of the checkbox to match the menu item title, b) restore the checked state of both the menu checkable, and our extra checkbox, and c) add an onClicked() listener for our extra checkbox. In this code I am persisting the state of the checkbox in a RetainedFragment.
// Set the check state of an actionbar item that has its actionLayout set to a layout
// containing a checkbox with the ID action_item_checkbox.
private void setActionBarCheckboxChecked(MenuItem it, boolean checked)
{
if (it == null)
return;
it.setChecked(checked);
// Since it is shown as an action, and not in the sub-menu we have to manually set the icon too.
CheckBox cb = (CheckBox)it.getActionView().findViewById(R.id.action_item_checkbox);
if (cb != null)
cb.setChecked(checked);
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater)
{
inflater.inflate(R.menu.menu_main, menu);
super.onCreateOptionsMenu(menu, inflater);
// Restore the check state e.g. if the device has been rotated.
final MenuItem logItem = menu.findItem(R.id.menu_action_logging);
setActionBarCheckboxChecked(logItem, mRetainedFragment.getLoggingEnabled());
CheckBox cb = (CheckBox)logItem.getActionView().findViewById(R.id.action_item_checkbox);
if (cb != null)
{
// Set the text to match the item.
cb.setText(logItem.getTitle());
// Add the onClickListener because the CheckBox doesn't automatically trigger onOptionsItemSelected.
cb.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
onOptionsItemSelected(logItem);
}
});
}
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_action_logging:
// Toggle the checkbox.
setActionBarCheckboxChecked(item, !item.isChecked());
// Do whatever you want to do when the checkbox is changed.
mRetainedFragment.setLoggingEnabled(item.isChecked());
return true;
default:
break;
}
return false;
}