I'm currently writing a simple application that uses 2 buttons anchored with Pop Up Menus that will display when the button is pressed. That was simple enough, however i'm having trouble with onMenuItemClick() method, which I want to use to change the text of the button to the menu item that was clicked.
Since I have two Pop Up Menus, each with 3 items, does this mean I would have to write 6 different if statements in the onMenuItemClick(), each one attempting to detect which item from which menu was clicked? Or is there a more simple way of doing this, for example specifying 2 onMenuItemClick() methods, each linked to the separate 2 menus?
public class MainActivity extends AppCompatActivity implements OnMenuItemClickListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void showColourPopUpMenu(View v){
PopupMenu coloursPopUpMenu = new PopupMenu(this, v);
coloursPopUpMenu.setOnMenuItemClickListener(this);
coloursPopUpMenu.inflate(R.menu.colours_menu);
coloursPopUpMenu.show();
}
public void showShapePopUpMenu(View v){
PopupMenu shapesPopUpMenu = new PopupMenu(this, v);
shapesPopUpMenu.setOnMenuItemClickListener(this);
shapesPopUpMenu.inflate(R.menu.shape_menu);
shapesPopUpMenu.show();
}
#Override
public boolean onMenuItemClick(MenuItem item) {
//How to determine which menu clicked?
return false;
}
}
#Override
public boolean onMenuItemClick(MenuItem item) {
int id = item.getItemId()
switch(id) {
case R.id.item1:
return true;
case R.id.item2:
return true;
default:
return false;
}
}
Create the listener when asigning it.
popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
#Override
public boolean onMenuItemClick(MenuItem item) {
return true;
}
});
It's not possible directly. You'd at least need to map the item ids item.getItemId() to the menu (button) they're connected to.
Maybe a little simpler might be using groups like: menu/colours_menu.xml
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<group android:id="#+id/colours_menu" >
<item android:id="#+id/item1" ... />
<item android:id="#+id/item2" ... />
<item android:id="#+id/item3" ... />
</group>
</menu>
With item.getGroupId() you'd get the group ids and only need to map these to the buttons:
#Override
public boolean onMenuItemClick(MenuItem item) {
if (item.getGroupId() == R.id.colours_menu) {
// edit colors menu
} else {
// edit shape menu
}
}
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 have generated a popUp Menu on button click (as the layout is custom layout so couldn't use onCreateOptionsMenu). Everything is working fine except that the menu looks odd. It has got a shadow behind it which doesn't seem to go well with the app. Is there any way in which I can remove the shadow or make the popup menu look like the menu generated using onCreateOptionsMenu.
Below is the image of my popup Menu
Code: (options_menu.xml)
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="#+id/option1" android:title="#string/option1"
android:orderInCategory="101" android:showAsAction="always|withText" />
<item android:id="#+id/option2" android:title="#string/option2"
android:orderInCategory="102" android:showAsAction="always|withText" />
</menu>
Activity:
popMenuBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Context wrapper = new ContextThemeWrapper(MenuActivity.this, myPopupMenuTextAppearance);
mPopupMenu = new PopupMenu(wrapper, v);
MenuInflater menuInflater = mPopupMenu.getMenuInflater();
menuInflater.inflate(R.menu.options_menu, mPopupMenu.getMenu());
mPopupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()) {
case R.id.option1:
startActivity(new Intent(this, XYZ.class));
return true;
case R.id.option2:
someFunction();
return true;
default:
Toast.makeText(this,"You Clicked : " + item.getTitle(),Toast.LENGTH_SHORT).show();
return true;
}
}
});
mPopupMenu.show();
}
});
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.
i am doing a android application for tablet in that
i have a gridView in a view pager
what i want to do is,
i want to add menu to imageview in the gridView like google books
Please see this image for reference
http://i.stack.imgur.com/cf4Or.jpg
i tried placing this in the gridView imageadaptor , no luck
public boolean onOptionsItemSelected(MenuItem item) {
// my code
}
Thanks for your time
You need to use PopupMenu:
http://developer.android.com/reference/android/widget/PopupMenu.html
You need to setup a PopupMenu giving a view as an anchor + specify the menu recourse that will be used here. Of course this should be done inside a OnClickListener for your view.
anchorView.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View view) {
PopupMenu popupMenu = new PopupMenu(context, anchorView);
popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()) {
case R.id.item_one:
// item one clicked
return true;
case R.id.item_two:
// item two clicked
return true;
}
return false;
}
);
popupMenu.inflate(R.menu.popup_menu);
popupMenu.show();
}
});
Define a standard menu resource - here is your popup_menu.xml:
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:id="#+id/item_one"
android:title="Item one"/>
<item
android:id="#+id/item_two"
android:title="Item two"/>
</menu>
Here is a nice tutorial that you can look at:
http://javatechig.com/android/popup-menu-in-android-example
yourImageViewObject.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
PopupMenu popup = new PopupMenu(activity, v);
/** Adding menu items to the popumenu */
popup.getMenuInflater().inflate(R.menu.main, popup.getMenu());
popup.setOnMenuItemClickListener(new OnMenuItemClickListener() {
#Override
public boolean onMenuItemClick(MenuItem item) {
// TODO Auto-generated method stub
switch (item.getItemId()) {
case R.id.spam:
Toast.makeText(activity, "Spam clicked",
Toast.LENGTH_SHORT).show();
break;
case R.id.blockuser:
Toast.makeText(activity, " Block user clicked",
Toast.LENGTH_SHORT).show();
break;
case R.id.remove:
Toast.makeText(activity, "Remove clicked",
Toast.LENGTH_SHORT).show();
break;
default:
break;
}
return false;
}
});
popup.show();
}
});
menu file main.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:id="#+id/spam"
android:title="Spam"/>
<item
android:id="#+id/blockuser"
android:title="Block User"/>
<item
android:id="#+id/remove"
android:title="Remove"/>
</menu>
put above main.xml in menu folder inside res folder
What you need is a PopupMenu. Create a view that can act as the anchor for the menu and add the PopupMenu as follows:
PopupMenu myPopup = new PopupMenu(context, myAnchor);
myAnchor.setOnTouchListener(myPopup.getDragToOpenListener());
You can follow the below steps... I hope this may help you
Step 1 : Create a menu items in menu resource folder
Somewhat like this :
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:id="#+id/menuitemone"
android:title="Cut"/>
<item android:id="#+id/menuitemtwo"
android:title="Copy" />
<item android:id="#+id/menuitemthree"
android:title="Paste"/>
</menu>
Step 2: Define an Image view for your individual griditem layout(according to your choice of placement)
Step 3: Define ImageView click listner in your BaseAdaptor class
Step 4: In onclick listner paste this code to show drop down menu
PopupMenu popup = new PopupMenu(MainActivity.this, arg1);
popup.getMenuInflater().inflate(R.menu.menuname, popup.getMenu());
popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
public boolean onMenuItemClick(MenuItem item) {
Log.i("TEST",item.getTitle());
return true;
}
});
popup.show();
You may need to see if you want a custom design for the same.
Google is your friend.
I have some items in an ActionBar sub menu which I would like to conditionally disable, because they are not applicable for some contexts. I would like them to appear disabled (greyed out) to discourage users from clicking them; but if clicked, I would like to show a toast informing the user of why it is disabled ("can't do A because there is no B", etc). However, if I call MenuItem.setEnabled(false), it seems all the menu item click events do not occur. So, how do I detect click on the disabled menu item?
public class Temp extends Activity implements OnMenuItemClickListener
{
boolean mConditional = true;
protected void onCreate(Bundle state)
{
super.onCreate(state);
}
public boolean onMenuOpened(int featureId, Menu menu)
{
MenuItem item = (MenuItem) menu.findItem(R.id.item2);
if(item != null && mConditional)
{
item.setEnabled(false);
item.setOnMenuItemClickListener(this);
}
return super.onMenuOpened(featureId, menu);
}
#Override
public boolean onMenuItemClick(MenuItem item)
{
//does not fire if item is disabled
Log.e("", item.getTitle().toString());
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item)
{
//does not fire if item is disabled
Log.e("", item.getTitle().toString());
return super.onOptionsItemSelected(item);
}
#Override
public boolean onMenuItemSelected(int featureId, MenuItem item)
{
//does not fire if item is disabled
Log.e("", item.getTitle().toString());
return super.onMenuItemSelected(featureId, item);
}
#Override
public boolean onCreateOptionsMenu(Menu menu)
{
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main, menu);
return true;
}
}
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="#+id/menu"
android:icon="#drawable/ic_launcher"
android:showAsAction="always"
android:title="menu">
<menu>
<item
android:id="#+id/item1"
android:showAsAction="always"
android:title="item 1"/>
<item
android:id="#+id/item2"
android:showAsAction="always"
android:title="item 2"/>
<item
android:id="#+id/item3"
android:showAsAction="always"
android:title="item 3"/>
</menu>
</item>
</menu>
You cannot use setEnabled for this. You need to keep menu items enabled all the time and simulate the "disabled" state by changing the drawable (or modifying it using porterduff filter - have a look at this question on how to dim images in android). Separately, you need to keep a flag indicating the state of the item - tag of the menu item is a good option. Ideally, you'd have something like this:
private void setMenuItemEnable(MenuItem item, boolean enabled) {
int curstate = ((Integer)item.getTag()).intValue();
if(curState == 1 && enabled || curstate == 0 && !enabled) {
return;
}
if(enabled) {
... //update image to remove dimming
item.setTag(1);
}
else {
... //update image by dimming it
item.setTag(0);
}
}
Finally, in your onOptionsItemSelected() method, check the tag of the chosen menu item and either perform the action if the tag is 1 or display the toast if the tag is 0. Visually it will be just what you want, and functionally it'll do what you're after.