Join FlipAndroid.COM Telegram Group: https://t.me/joinchat/F_aqThGkhwcLzmI49vKAiw


PopupMenu con iconos

Por supuesto, estamos tratando aquí con el SDK 11 y más arriba.

Tengo la intención de hacer algo similar a esto: Introduzca aquí la descripción de la imagen

Al lado de cada elemento de ese PopupMenu , me gustaría colocar un icono .

He creado un archivo XML y lo he colocado en /menu :

 <menu xmlns:android="http://schemas.android.com/apk/res/android" > <item android:id="@+id/action_one" android:title="Sync" android:icon="@android:drawable/ic_popup_sync" /> <item android:id="@+id/action_two" android:title="About" android:icon="@android:drawable/ic_dialog_info" /> </menu> 

Como usted notó, en el archivo xml estoy definiendo los iconos que quiero, sin embargo, cuando el menú emergente muestra, se muestra sin los iconos. ¿Qué debo hacer para que aparezcan esos 2 iconos?

  • Color de texto del menú emergente de Android (AppCompat)
  • Cómo crear un PopupMenu personalizado en Android
  • Cómo cambiar la fuente de elementos de PopupMenu
  • Manejo de elementos del menú emergente
  • PopupMenu no se encuentra correctamente dentro de RecyclerView
  • Menú emergente personalizado de Android con conmutador
  • Cómo evitar que el menú emergente se cierre en la casilla de verificación haga clic
  • Cómo configurar el fondo de Android PopupMenu a Blanco
  • 12 Solutions collect form web for “PopupMenu con iconos”

    Lo implementaría de otra manera:

    Crear un diseño PopUpWindow :

     <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/llSortChangePopup" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/sort_popup_background" android:orientation="vertical" > <TextView android:id="@+id/tvDistance" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/distance" android:layout_weight="1.0" android:layout_marginLeft="20dp" android:paddingTop="5dp" android:gravity="center_vertical" android:textColor="@color/my_darker_gray" /> <ImageView android:layout_marginLeft="11dp" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/sort_popup_devider" android:contentDescription="@drawable/sort_popup_devider"/> <TextView android:id="@+id/tvPriority" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/priority" android:layout_weight="1.0" android:layout_marginLeft="20dp" android:gravity="center_vertical" android:clickable="true" android:onClick="popupSortOnClick" android:textColor="@color/my_black" /> <ImageView android:layout_marginLeft="11dp" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/sort_popup_devider" android:contentDescription="@drawable/sort_popup_devider"/> <TextView android:id="@+id/tvTime" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/time" android:layout_weight="1.0" android:layout_marginLeft="20dp" android:gravity="center_vertical" android:clickable="true" android:onClick="popupSortOnClick" android:textColor="@color/my_black" /> <ImageView android:layout_marginLeft="11dp" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/sort_popup_devider" android:contentDescription="@drawable/sort_popup_devider"/> <TextView android:id="@+id/tvStatus" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/status" android:layout_weight="1.0" android:layout_marginLeft="20dp" android:gravity="center_vertical" android:textColor="@color/my_black" android:clickable="true" android:onClick="popupSortOnClick" android:paddingBottom="10dp"/> </LinearLayout> 

    Y luego crear el PopUpWindow en su Activity :

      // The method that displays the popup. private void showStatusPopup(final Activity context, Point p) { // Inflate the popup_layout.xml LinearLayout viewGroup = (LinearLayout) context.findViewById(R.id.llStatusChangePopup); LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); View layout = layoutInflater.inflate(R.layout.status_popup_layout, null); // Creating the PopupWindow changeStatusPopUp = new PopupWindow(context); changeStatusPopUp.setContentView(layout); changeStatusPopUp.setWidth(LinearLayout.LayoutParams.WRAP_CONTENT); changeStatusPopUp.setHeight(LinearLayout.LayoutParams.WRAP_CONTENT); changeStatusPopUp.setFocusable(true); // Some offset to align the popup a bit to the left, and a bit down, relative to button's position. int OFFSET_X = -20; int OFFSET_Y = 50; //Clear the default translucent background changeStatusPopUp.setBackgroundDrawable(new BitmapDrawable()); // Displaying the popup at the specified location, + offsets. changeStatusPopUp.showAtLocation(layout, Gravity.NO_GRAVITY, px + OFFSET_X, py + OFFSET_Y); } 

    Finalmente pop que hasta onClick de un botón o cualquier otra cosa:

      imTaskStatusButton.setOnClickListener(new OnClickListener() { public void onClick(View v) { int[] location = new int[2]; currentRowId = position; currentRow = v; // Get the x, y location and store it in the location[] array // location[0] = x, location[1] = yvgetLocationOnScreen(location); //Initialize the Point with x, and y positions point = new Point(); point.x = location[0]; point.y = location[1]; showStatusPopup(TasksListActivity.this, point); } }); 

    Buen ejemplo para PopUpWindow :

    http://androidresearch.wordpress.com/2012/05/06/how-to-create-popups-in-android/

    De esta manera funciona si utilizas AppCompat v7. Es un poco hacky, pero significativamente mejor que usar la reflexión y le permite seguir utilizando el núcleo de Android PopupMenu:

     PopupMenu menu = new PopupMenu(getContext(), overflowImageView); menu.inflate(R.menu.popup); menu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { ... }); MenuPopupHelper menuHelper = new MenuPopupHelper(getContext(), (MenuBuilder) menu.getMenu(), overflowImageView); menuHelper.setForceShowIcon(true); menuHelper.show(); 

    Res / menu / popup.xml

     <?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/menu_share_location" android:title="@string/share_location" android:icon="@drawable/ic_share_black_24dp"/> </menu> 

    Esto resulta en el menú emergente con el icono que se define en el archivo de recursos del menú:

    Introduzca aquí la descripción de la imagen

    El menú emergente de Android tiene un método oculto para mostrar el icono del menú. Utilice la reflexión de Java para habilitarla como fragmento de código a continuación.

     public static void setForceShowIcon(PopupMenu popupMenu) { try { Field[] fields = popupMenu.getClass().getDeclaredFields(); for (Field field : fields) { if ("mPopup".equals(field.getName())) { field.setAccessible(true); Object menuPopupHelper = field.get(popupMenu); Class<?> classPopupHelper = Class.forName(menuPopupHelper .getClass().getName()); Method setForceIcons = classPopupHelper.getMethod( "setForceShowIcon", boolean.class); setForceIcons.invoke(menuPopupHelper, true); break; } } } catch (Throwable e) { e.printStackTrace(); } } 

    He resuelto mi problema de la manera más simple posible nunca, nunca esperaba una sencillez de este tipo:

    En main.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> 

    En 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; } 

    Eso fue un truco mediante el uso de un submenú

    Lea el código fuente de PopupMenu. Podemos mostrar el icono por el siguiente código:

     Field field = popupMenu.getClass().getDeclaredField("mPopup"); field.setAccessible(true); MenuPopupHelper menuPopupHelper = (MenuPopupHelper) field.get(popupMenu); menuPopupHelper.setForceShowIcon(true); 

    Pero MenuPopupHelper.java está en el paquete interno android. Así que debemos usar la Reflexión:

      PopupMenu popupMenu = new PopupMenu(this, anchor); popupMenu.getMenuInflater().inflate(R.menu.process, popupMenu.getMenu()); try { Field field = popupMenu.getClass().getDeclaredField("mPopup"); field.setAccessible(true); Object menuPopupHelper = field.get(popupMenu); Class<?> cls = Class.forName("com.android.internal.view.menu.MenuPopupHelper"); Method method = cls.getDeclaredMethod("setForceShowIcon", new Class[]{boolean.class}); method.setAccessible(true); method.invoke(menuPopupHelper, new Object[]{true}); } catch (Exception e) { e.printStackTrace(); } popupMenu.show(); 

    Menú emergente con el icono que utiliza MenuBuilder y 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> 

    Introduzca aquí la descripción de la imagen

    Si desea mostrar el icono en el menú emergente, eche un vistazo a https://github.com/shehabic/Droppy , es bastante genial y fácil de usar

    List_item_menu.xml directorio in / res / 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/locale" android:title="Localizar" android:icon="@mipmap/ic_en_farmacia_ico" app:showAsAction="always"> </item> <item android:id="@+id/delete" android:title="Eliminar" android:icon="@mipmap/ic_eliminar_ico" app:showAsAction="always"> </item> </menu> 

    En mi actividad

     private void showPopupOption(View v){ PopupMenu popup = new PopupMenu(getContext(), v); popup.getMenuInflater().inflate(R.menu.list_item_menu, popup.getMenu()); popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { public boolean onMenuItemClick(MenuItem menu_item) { switch (menu_item.getItemId()) { case R.id.locale: break; case R.id.delete: break; } return true; } }); MenuPopupHelper menuHelper = new MenuPopupHelper(getContext(), (MenuBuilder) popup.getMenu(), v); menuHelper.setForceShowIcon(true); menuHelper.setGravity(Gravity.END); menuHelper.show(); } 

    resultado

    menú emergente

    No es un menú emergente, es un hilandero allí.

    Aquí está un enlace a la guía de spinners api

    Basado en @Ajay respuesta … aquí es lo que hice

      @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.add_task, menu); // for the two icons in action bar return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.menu: View menuItemView = findViewById(R.id.menu); MenuBuilder menuBuilder =new MenuBuilder(this); MenuInflater inflater = new MenuInflater(this); inflater.inflate(R.menu.popup, menuBuilder); MenuPopupHelper optionsMenu = new MenuPopupHelper(this, menuBuilder, menuItemView); optionsMenu.setForceShowIcon(true); optionsMenu.show(); default: return super.onOptionsItemSelected(item); } } 

    surgir

     <?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/opt1" android:icon="@drawable/change_pic" android:title="Change Picture" /> <item android:id="@+id/opt2" android:icon="@drawable/change_pin" android:title="Change Password" /> <item android:id="@+id/opt3" android:icon="@drawable/sign_out" android:title="Sign Out" /> </menu> 

    Captura de pantalla

    Introduzca aquí la descripción de la imagen

    Estaba intentando la respuesta de @Stephen Kidson y la sugerencia de @ david.schereiber, y me di cuenta de que no existe tal método setOnMenuItemClickListener en MenuBuilder . Jugué con el código fuente de la v7 un poco y encontré esta solución:

      MenuBuilder menuBuilder = new MenuBuilder(mContext); new SupportMenuInflater(mContext).inflate(R.menu.my_menu, menuBuilder); menuBuilder.setCallback(new MenuBuilder.Callback() { @Override public boolean onMenuItemSelected(MenuBuilder menu, MenuItem menuItem) { // your "setOnMenuItemClickListener" code goes here switch (menuItem.getItemId()) { case R.id.menu_id1: // do something 1 return true; case R.id.menu_id2: // do something 2 return true; } return false; } @Override public void onMenuModeChange(MenuBuilder menu) { } }); MenuPopupHelper menuHelper = new MenuPopupHelper(mContext, menuBuilder, v); menuHelper.setForceShowIcon(true); // show icons!!!!!!!! menuHelper.show(); 

    La clase MenuPopupHelper en AppCompat tiene la anotación @hide . Si eso es una preocupación, o si no puede usar AppCompat por cualquier razón, hay otra solución utilizando un Spannable en el título MenuItem que contiene tanto el icono como el texto del título.

    Los pasos principales son:

    • Infla tu PopupMenu con un archivo xml de menu
    • Si alguno de los elementos tiene un icono, haga esto para todos los elementos:
      • Si el elemento no tiene un icono, cree un icono transparente. Esto garantiza que los elementos sin iconos se alinearán con elementos con iconos
      • Cree un SpannableStringBuilder contiene el icono y el título
      • SpannableStringBuilder el título del elemento de menú en SpannableStringBuilder
      • Establezca el icono del elemento de menú en nulo, "por si acaso"

    Pros: No hay reflexión. No usa ningún apis oculto. Puede trabajar con el framework PopupMenu.

    Contras: Más código. Si tiene un submenú sin un icono, tendrá un acolchado izquierdo no deseado en una pequeña pantalla.


    Detalles:

    En primer lugar, defina un tamaño para el icono en un archivo dimens.xml :

     <dimen name="menu_item_icon_size">24dp</dimen> 

    A continuación, algunos métodos para mover los iconos definidos en xml en los títulos:

     /** * Moves icons from the PopupMenu's MenuItems' icon fields into the menu title as a Spannable with the icon and title text. */ public static void insertMenuItemIcons(Context context, PopupMenu popupMenu) { Menu menu = popupMenu.getMenu(); if (hasIcon(menu)) { for (int i = 0; i < menu.size(); i++) { insertMenuItemIcon(context, menu.getItem(i)); } } } /** * @return true if the menu has at least one MenuItem with an icon. */ private static boolean hasIcon(Menu menu) { for (int i = 0; i < menu.size(); i++) { if (menu.getItem(i).getIcon() != null) return true; } return false; } /** * Converts the given MenuItem's title into a Spannable containing both its icon and title. */ private static void insertMenuItemIcon(Context context, MenuItem menuItem) { Drawable icon = menuItem.getIcon(); // If there's no icon, we insert a transparent one to keep the title aligned with the items // which do have icons. if (icon == null) icon = new ColorDrawable(Color.TRANSPARENT); int iconSize = context.getResources().getDimensionPixelSize(R.dimen.menu_item_icon_size); icon.setBounds(0, 0, iconSize, iconSize); ImageSpan imageSpan = new ImageSpan(icon); // Add a space placeholder for the icon, before the title. SpannableStringBuilder ssb = new SpannableStringBuilder(" " + menuItem.getTitle()); // Replace the space placeholder with the icon. ssb.setSpan(imageSpan, 1, 2, 0); menuItem.setTitle(ssb); // Set the icon to null just in case, on some weird devices, they've customized Android to display // the icon in the menu... we don't want two icons to appear. menuItem.setIcon(null); } 

    Por último, cree su PopupMenu y utilice los métodos anteriores antes de mostrarlo:

     PopupMenu popupMenu = new PopupMenu(view.getContext(), view); popupMenu.inflate(R.menu.popup_menu); insertMenuItemIcons(textView.getContext(), popupMenu); popupMenu.show(); 

    Captura de pantalla: captura de pantalla

    FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.