I have 4 items in the menu and 1 button Rec / Stop. I want, when the Rec button is active and records, the other 4 items in the menu items are disabled. Please help me.
this is activity_main.xml
<ToggleButton
android:id="#+id/recStop"
android:layout_width="65dp"
android:layout_height="65dp"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="100dp"
android:background="#drawable/tbutton"
android:text=""
android:textOff=""
android:textOn="" />
this is tbutton.xml
<item android:drawable="#drawable/rec"
android:state_checked="false" />
<item android:drawable="#drawable/stop"
android:state_checked="true" />
this is MainActivity.java
private ToggleButton toggleButton;
toggleButton = (ToggleButton) findViewById(R.id.recStop);
// Button Rec / Stop
toggleButton.setOnCheckedChangeListener(new OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
if (isChecked) {
speech.setRecognitionListener(VoiceRecognitionActivity.this);
progressBar.setVisibility(View.VISIBLE);
progressBar.setIndeterminate(true);
speech.startListening(recognizerIntent);
} else {
progressBar.setIndeterminate(false);
progressBar.setVisibility(View.INVISIBLE);
speech.stopListening();
speech.destroy();
}
}
});
this is MainActivity.java
// Menu items
public boolean onOptionsItemSelected(MenuItem item){
switch (item.getItemId()) {
case R.id.copy:
break;
}
switch (item.getItemId()) {
case R.id.share:
break;
}
switch (item.getItemId()) {
case R.id.clear:
break;
}
switch (item.getItemId()) {
case R.id.about:
break;
}
return super.onOptionsItemSelected(item);
}
Inside each condition of your switch...case, check the status of togglebutton and if its checked avoid further actions in it. Also don't use multiple switch, you must define multiple cases inside it see the code below.
switch (item.getItemId()) {
case R.id.copy:
if(toggleButton.isChecked()) {
//display warning message
} else {
// your regular code here
}
break;
case R.id.share:
if(toggleButton.isChecked()) {
//display warning message
} else {
// your regular code here
}
break;
case R.id.clear:
if(toggleButton.isChecked()) {
//display warning message
} else {
// your regular code here
}
break;
case R.id.about:
if(toggleButton.isChecked()) {
//display warning message
} else {
// your regular code here
}
break;
}
You can achieve that with this code
switch (item.getItemId()) {
case R.id.copy:
if(toggleButton.isChecked()) {
menu.findItem(R.id.copy).setEnabled(false);
} else {
menu.findItem(R.id.copy).setEnabled(true);
}
break;
//you do the same for the rest of menu buttons
}
I tried this solution, but it doesn't work as I expected. Here is my code, and this is what i have tried.
PopupMenu popup = new PopupMenu(TableActivity.this, view);
popup.setOnMenuItemClickListener(TableActivity.this);
menu = popup.getMenu();
popup.inflate(R.menu.popup_shift);
popup.show();
popup.setOnMenuItemClickListener(this);
#Override
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_merge:
if(tableDbList.get(positionShift).getMergeTableId()== 0) {
//this is the condition to show/hide popup menuitem
popup.getMenu().findItem(R.id.menu_merge).setVisible(false);
}else {
checkPinCode.checkPinCodemethod(TableActivity.this, "mergeCancel");
}
}
return true;
}
You are trying to change visibility on MenuItem click . It will work but popupMenu will dismiss just after click . So it does not make any sense.
If your requirement is to show items on some condition you should set visibility before show(). Below is a simple example .
private void showPopup() {
final PopupMenu popup = new PopupMenu(MainActivity.this, view);
popup.getMenuInflater().inflate(R.menu.popup_shift, popup.getMenu());
if(someCondition){
popup.getMenu().findItem(R.id.menu_merge).setVisible(false);
}
popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
public boolean onMenuItemClick(MenuItem item) {
Toast.makeText(MainActivity.this, "You Clicked : " + item.getTitle(), Toast.LENGTH_SHORT).show();
return true;
}
});
popup.show();
}
I really like the new PopupMenu we got in 3.0, but I just can't display any icons next to the menu items in it. I'm inflating the menu from the .xml below:
<item android:id="#+id/menu_delete_product"
android:icon="#drawable/sym_action_add"
android:title="delete"
android:showAsAction="ifRoom|withText" />
<item android:id="#+id/menu_modify_product"
android:icon="#drawable/sym_action_add"
android:title="modify"
android:showAsAction="ifRoom|withText" />
<item android:id="#+id/menu_product_details"
android:icon="#drawable/sym_action_add"
android:title="details"
android:showAsAction="ifRoom|withText" />
With this code:
image.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
PopupMenu pop = new PopupMenu(getActivity(), v);
pop.getMenuInflater().inflate(R.menu.shelves_details_menu, pop.getMenu());
pop.show();
}
});
I can't get the icons to show up, am I missing something?
Contribution to the solution provided by Gaelan Bolger.
Use this code if you get a "IllegalAccessException: access to field not allowed".
PopupMenu popup = new PopupMenu(mContext, view);
try {
Field[] fields = popup.getClass().getDeclaredFields();
for (Field field : fields) {
if ("mPopup".equals(field.getName())) {
field.setAccessible(true);
Object menuPopupHelper = field.get(popup);
Class<?> classPopupHelper = Class.forName(menuPopupHelper
.getClass().getName());
Method setForceIcons = classPopupHelper.getMethod(
"setForceShowIcon", boolean.class);
setForceIcons.invoke(menuPopupHelper, true);
break;
}
}
} catch (Exception e) {
e.printStackTrace();
}
prepareMenu(popup.getMenu());
popup.show();
text
If you're willing to be a bit adventurous, look at Google's source code for PopupMenu. Create your own class i.e. MyPopupMenu that is the same as Google's PopupMenu class, but make one slight change.
In PopupMenu's constructor:
public MyPopupMenu(Context context, View anchor) {
// TODO Theme?
mContext = context;
mMenu = new MenuBuilder(context);
mMenu.setCallback(this);
mAnchor = anchor;
mPopup = new MenuPopupHelper(context, mMenu, anchor);
mPopup.setCallback(this);
mPopup.setForceShowIcon(true); //ADD THIS LINE
}
use the method setForceShowIcon to force it to show the icon. You can also just expose a public method to set this flag as well depending on your needs.
I was able to show the icons using reflection. It may not be the most elegant solution but it works.
try {
Class<?> classPopupMenu = Class.forName(popupMenu
.getClass().getName());
Field mPopup = classPopupMenu.getDeclaredField("mPopup");
mPopup.setAccessible(true);
Object menuPopupHelper = mPopup.get(popupMenu);
Class<?> classPopupHelper = Class.forName(menuPopupHelper
.getClass().getName());
Method setForceIcons = classPopupHelper.getMethod(
"setForceShowIcon", boolean.class);
setForceIcons.invoke(menuPopupHelper, true);
} catch (Exception e) {
e.printStackTrace();
}
We can use sub-menu model. So, we don't need to write method for showing popup menu, it will be showing automacally. Have a look:
menu.xml
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:id="#+id/action_more"
android:icon="#android:drawable/ic_menu_more"
android:orderInCategory="1"
android:showAsAction="always"
android:title="More">
<menu>
<item
android:id="#+id/action_one"
android:icon="#android:drawable/ic_popup_sync"
android:title="Sync"/>
<item
android:id="#+id/action_two"
android:icon="#android:drawable/ic_dialog_info"
android:title="About"/>
</menu>
</item>
</menu>
in MainActivity.java
#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);
return true;
}
The result is:
before use method popup.show(),make a MenuPopupHelper instance and call method setForceShowIcon(true),like this
try {
Field mFieldPopup=popupMenu.getClass().getDeclaredField("mPopup");
mFieldPopup.setAccessible(true);
MenuPopupHelper mPopup = (MenuPopupHelper) mFieldPopup.get(popupMenu);
mPopup.setForceShowIcon(true);
} catch (Exception e) {
}
The easiest way I found is that to use 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) {}
});
// Display the 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>
I found a native solution for this, using MenuPopupHelper.setForceShowIcon(true).
private void createMenu(int menuRes, View anchor, MenuBuilder.Callback callback) {
Context context = anchor.getContext();
NavigationMenu navigationMenu = new NavigationMenu(context);
navigationMenu.setCallback(callback);
SupportMenuInflater supportMenuInflater = new SupportMenuInflater(context);
supportMenuInflater.inflate(menuRes, navigationMenu);
MenuPopupHelper menuPopupHelper = new MenuPopupHelper(context, navigationMenu, anchor);
menuPopupHelper.setForceShowIcon(true);
menuPopupHelper.show();
}
Usage
private void initMenu(View view) {
view.findViewById(R.id.myButton).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
createMenu(R.menu.help_menu, view, new MenuBuilder.Callback() {
#Override
public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) {
switch (item.getItemId()) {
case R.id.id1:
// Do something
break;
case R.id.id2:
// Do something
break;
case R.id.id3:
// Do something
break;
}
return true;
}
#Override
public void onMenuModeChange(MenuBuilder menu) {
}
});
}
});
}
Along the line of using reflection and without the need to use MenuPopupHelper, you can add
if (popup.getMenu() instanceof MenuBuilder) {
//noinspection RestrictedApi
((MenuBuilder) popup.getMenu()).setOptionalIconsVisible(true);
}
prior to inflating the menu
PopupMenu will not display icons. You can use an ActionBar.
http://developer.android.com/guide/topics/ui/actionbar.html
Some of the solutions above will work with the reflection hack,
Just sharing this: I've recently came across the same issues, but I also wanted to create a more customized thing (adding custom view in the menu) so I created the following lib.
https://github.com/shehabic/Droppy
If you're using AndroidX, which changed the visibility of MenuPopupHelper to package-private, you can avoid the cost of reflection by creating a wrapper class with the same package name.
This exposes package-private members to public.
package androidx.appcompat.widget // Create this package in your project's /src/main/java
import android.annotation.SuppressLint
class PopupMenuWrapper(val t: PopupMenu) {
#SuppressLint("RestrictedApi")
fun setForceShowIcon(show: Boolean) { // Public method
t.mPopup.setForceShowIcon(show)
}
}
fun PopupMenu.wrap() = PopupMenuWrapper(this)
Then call the hidden function as you normally would.
val popup = PopupMenu(anchor.context, anchor)
popup.wrap().setForceShowIcon(true)
popup.show()
If you want to prevent using RestrictedApi use this extention function:
fun PopupMenu.forcePopUpMenuToShowIcons() {
try {
val method = menu.javaClass.getDeclaredMethod(
"setOptionalIconsVisible",
Boolean::class.javaPrimitiveType
)
method.isAccessible = true
method.invoke(menu, true)
} catch (e: Exception) {
e.printStackTrace()
}
}
You can use the setForceShowIcon (true)
PopupMenu(context, view).apply {
setForceShowIcon(true)
menuInflater.inflate(R.menu.menu_edit_professional_experience, menu)
setOnMenuItemClickListener { item ->
Toast.makeText(view.context, "YOU clcick", Toast.LENGTH_LONG).show()
true
}
}.show()
Use setForceShowIcon(true)
The PopupMenu cannot be fully customized. Below you find a general solution to make your PopupMenu customizable via a custom layout. Having that, you can experiment a lot more with different layouts. Cheers.
1 - The Custom PopupMenu class:
public class PopupMenuCustomLayout {
private PopupMenuCustomOnClickListener onClickListener;
private Context context;
private PopupWindow popupWindow;
private int rLayoutId;
private View popupView;
public PopupMenuCustomLayout(Context context, int rLayoutId, PopupMenuCustomOnClickListener onClickListener) {
this.context = context;
this.onClickListener = onClickListener;
this.rLayoutId = rLayoutId;
LayoutInflater inflater = (LayoutInflater) context.getSystemService(LAYOUT_INFLATER_SERVICE);
popupView = inflater.inflate(rLayoutId, null);
int width = LinearLayout.LayoutParams.WRAP_CONTENT;
int height = LinearLayout.LayoutParams.WRAP_CONTENT;
boolean focusable = true;
popupWindow = new PopupWindow(popupView, width, height, focusable);
popupWindow.setElevation(10);
LinearLayout linearLayout = (LinearLayout) popupView;
for (int i = 0; i < linearLayout.getChildCount(); i++) {
View v = linearLayout.getChildAt(i);
v.setOnClickListener( v1 -> { onClickListener.onClick( v1.getId()); popupWindow.dismiss(); });
}
}
public void setAnimationStyle( int animationStyle) {
popupWindow.setAnimationStyle(animationStyle);
}
public void show() {
popupWindow.showAtLocation( popupView, Gravity.CENTER, 0, 0);
}
public void show( View anchorView, int gravity, int offsetX, int offsetY) {
popupWindow.showAsDropDown( anchorView, 0, -2 * (anchorView.getHeight()));
}
public interface PopupMenuCustomOnClickListener {
public void onClick(int menuItemId);
}
}
2 - Your custom layout, e.g. linearlayout with horizontal layout. In this case I use a simple LinearLayout with TextView items. You can use Buttons, etc.
<?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="wrap_content"
android:background="#color/white"
android:orientation="horizontal">
<TextView
android:id="#+id/popup_menu_custom_item_a"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="A"
android:textAppearance="?android:textAppearanceMedium" />
<TextView
android:id="#+id/popup_menu_custom_item_b"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:text="B"
android:textAppearance="?android:textAppearanceMedium" />
// ...
</LinearLayout>
3 - Using the Custom PopupMenu like the normal PopupMenu.
PopupMenuCustomLayout popupMenu = new PopupMenuCustomLayout(
MainActivity.mainActivity, R.layout.popup_menu_custom_layout,
new PopupMenuCustomLayout.PopupMenuCustomOnClickListener() {
#Override
public void onClick(int itemId) {
// log statement: "Clicked on: " + itemId
switch (itemId) {
case R.id.popup_menu_custom_item_a:
// log statement: "Item A was clicked!"
break;
}
}
});
// Method 1: popupMenu.show();
// Method 2: via an anchor view:
popupMenu.show( anchorView, Gravity.CENTER, 0, 0);
I am trying create a menu list dynamically, i was able to create the menu option but every time i run my code the icon for the main item disappear: here is my code sample:
private static final int SUB_Menu_ONE = R.menu.settings;
private static final int SUB_Menu_TWO = R.menu.settings + 1;
private static final int SUB_Menu_THREE= R.menu.settings + 2;
private static final int SUB_Menu_FOUR = R.menu.settings + 3;
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.settings, menu);
return true;
}
// private Menu menu;
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
menu.clear();
menu.add(0, SUB_Menu_ONE, Menu.NONE, "Sub Menu Item 0");
menu.add(0, SUB_Menu_TWO, Menu.NONE, "Sub Menu Item 1");
menu.add(0, SUB_Menu_THREE, Menu.NONE, "Sub Menu Item 2");
menu.add(0, SUB_Menu_FOUR, Menu.NONE, "Sub Menu Item 3");
return super.onCreateOptionsMenu(menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
Intent inent;
switch (item.getItemId()) {
case SUB_Menu_ONE:
// doStuff();
break;
case SUB_Menu_TWO:
// doStuff();
break;
case SUB_Menu_THREE:
// doStuff();
break;
case SUB_Menu_FOUR:
// doStuff();
break;
default:
// If we got here, the user's action was not recognized.
// Invoke the superclass to handle it.
return super.onOptionsItemSelected(item);
}
return false;
}
Here is my XML Layout for Menu settings
<?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"
xmlns:compat="http://schemas.android.com/tools">
<!-- Settings, should always be in the overflow -->
<item android:id="#+id/action_settings"
android:title="#string/action_settings_title"
android:icon="#drawable/cuslistticketbutton"
app:showAsAction="always|withText"
android:actionLayout="#layout/custabview"
compat:showAsAction="ifRoom"
>
<!--<menu>-->
<!--<item-->
<!--android:id="#+id/menu_addticket"-->
<!--android:showAsAction="never"-->
<!--android:icon="#drawable/add_tickets"-->
<!--android:title=""-->
<!--compat:ignore="AppCompatResource,HardcodedText" />-->
<!--</menu>-->
</item>
</menu>
Any help is welcome
You have to set the icon programmatically.
menu.add(0, SUB_Menu_ONE, Menu.NONE, "PREMIUM (Live Video & Audio)").setIcon(R.drawable.icon);
Why can not I use setOnClickListener and setOnTouchListener in my program?
OnTouchListener works well, but I cen't run new activity?
what am I doing wrong?
for (final ShopCategory category : gallery.getShopCategories()) {
final Button button = new Button(this);
// ... etc
button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
runNewActivity(gallery.getShops(), category);
}
});
button.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN ) {
button.setTextColor(Color.parseColor("#333333"));
button.setBackgroundColor(Color.parseColor("#ffcc33"));
return true;
}
else if (event.getAction() == MotionEvent.ACTION_UP ) {
button.setTextColor(Color.WHITE);
button.setBackgroundColor(Color.parseColor("#333333"));
}
return false;
}
});
categoriesButtonsLL.addView(button);
You can do it better with using drawable selector to change button's show state rather than listen touch event.
(create a selector xml file in res/drawable, for example "button_bg.xml") :
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true"
android:drawable="#drawable/button_pressed" /> <!-- pressed -->
<item android:state_focused="true"
android:drawable="#drawable/button_focused" /> <!-- focused -->
<item android:drawable="#drawable/button_normal" /> <!-- default -->
</selector>
now edit your code like this:
for (final ShopCategory category : gallery.getShopCategories()) {
final Button button = new Button(this);
button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
runNewActivity(gallery.getShops(), category);
}
});
button.setBackgroundResource(R.drawable.button_bg);
categoriesButtonsLL.addView(button);
}
Quick guess here. But try returning false in your onTouch. Returning true in the ActionDown means that you handled the event and no further processing is necessary. So if ActionDown is handled, onClick never happens.