【问题标题】:Popup menu with icon on AndroidAndroid 上带有图标的弹出菜单
【发布时间】:2017-09-17 23:38:49
【问题描述】:

我的菜单xml代码menu.xml

<?xml version="1.0" encoding="utf-8"?><menu xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Single menu item 
     Set id, icon and Title for each menu item
-->

 <item android:id="@+id/back"
      android:icon="@drawable/back1"
        android:showAsAction="never"
      android:title="Back" />

<item android:id="@+id/My_Profile"
      android:icon="@drawable/myprofile"
       android:showAsAction="never"
      android:title="My Profile" />

<item android:id="@+id/Job_Alert"
      android:icon="@drawable/jobalert4"
       android:showAsAction="never"
      android:title="Job Alert !" />

<item android:id="@+id/saved_job"
      android:icon="@drawable/jobapplied"
      android:title="Saved Jobs"
       />


<item android:id="@+id/Logout"
      android:icon="@drawable/logout"
      android:title="Logout" /> 
</menu>

我正在像这样调用菜单 xml

     PopupMenu popup = new PopupMenu(getBaseContext(), v);
 popup.getMenuInflater().inflate(R.menu.menu,  popup.getMenu());
     popup.show();

但它不显示图标。

如何设置弹出菜单上的图标?

【问题讨论】:

  • 你在显示上下文菜单吗?
  • 我在点击顶部按钮时显示菜单
  • 查看我的答案,这可能对你有帮助。
  • 是的,我想要这样,并且我了解将布局 xml 文件用于菜单,但我对 showStatusPopup 方法一无所知,因为我是 android 新手,所以请给我一个简单的例子
  • 我已经在我的答案签出中提供了一个示例链接。 @user3145614

标签: android android-xml


【解决方案1】:

您可以使用MenuBuilderMenuPopupHelper 创建带有图标的弹出菜单。

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) {}
});

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>

【讨论】:

  • +1 是我见过的构建图标 + 文本菜单项的最简洁方式。但是,您是如何处理 onItemClick 方法的?
  • @iaindownie 我添加了代码来处理菜单点击。我认为这可能会对您有所帮助。
  • 太棒了,谢谢!这也应该是所有其他帖子的答案!比我见过的自定义/图标菜单要干净得多。
  • 我抓到了MenuBuilder constructor can only be called from within the same library group
【解决方案2】:

您可以通过使用Java反射调用隐藏方法来启用弹出菜单的图标,如下所示:

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();
    }
}

【讨论】:

    【解决方案3】:

    您可以按照此处所述使用反射: https://stackoverflow.com/a/18431605/4521603

    或者如果你使用 Xamarin / C#:

    添加:

    using Java.Lang.Reflect;
    

    然后在你的代码中使用它:

    PopupMenu puMenu = new PopupMenu(Activity, v)
    
    Field field = puMenu.Class.GetDeclaredField("mPopup");
    field.Accessible = true;
    Java.Lang.Object menuPopupHelper = field.Get(puMenu);
    Method setForceIcons = menuPopupHelper.Class.GetDeclaredMethod("setForceShowIcon", Java.Lang.Boolean.Type);
    setForceIcons.Invoke(menuPopupHelper, true);
    
    puMenu.Inflate (Resource.Menu.your_actions);
    puMenu.Show ();
    

    【讨论】:

      【解决方案4】:

      使用这个:

      /**
       * Copied from android.support.v7.widget.PopupMenu.
       * "mPopup.setForceShowIcon(true);" in the constructor does the trick :)
       * 
       * @author maikvlcek
       * @since 5:00 PM - 1/27/14
       */
      public class IconizedMenu implements MenuBuilder.Callback, MenuPresenter.Callback {
              private Context mContext;
              private MenuBuilder mMenu;
              private View mAnchor;
              private MenuPopupHelper mPopup;
              private OnMenuItemClickListener mMenuItemClickListener;
              private OnDismissListener mDismissListener;
      
              /**
               * Callback interface used to notify the application that the menu has closed.
               */
              public interface OnDismissListener {
                  /**
                   * Called when the associated menu has been dismissed.
                   *
                   * @param menu The PopupMenu that was dismissed.
                   */
                  public void onDismiss(IconizedMenu menu);
              }
      
              /**
               * Construct a new PopupMenu.
               *
               * @param context Context for the PopupMenu.
               * @param anchor Anchor view for this popup. The popup will appear below the anchor if there
               *               is room, or above it if there is not.
               */
              public IconizedMenu(Context context, View anchor) {
                  mContext = context;
                  mMenu = new MenuBuilder(context);
                  mMenu.setCallback(this);
                  mAnchor = anchor;
                  mPopup = new MenuPopupHelper(context, mMenu, anchor);
                  mPopup.setCallback(this);
                  mPopup.setForceShowIcon(true);
              }
      
              /**
               * @return the {@link android.view.Menu} associated with this popup. Populate the returned Menu with
               * items before calling {@link #show()}.
               *
               * @see #show()
               * @see #getMenuInflater()
               */
              public Menu getMenu() {
                  return mMenu;
              }
      
              /**
               * @return a {@link android.view.MenuInflater} that can be used to inflate menu items from XML into the
               * menu returned by {@link #getMenu()}.
               *
               * @see #getMenu()
               */
              public MenuInflater getMenuInflater() {
                  return new SupportMenuInflater(mContext);
              }
      
              /**
               * Inflate a menu resource into this PopupMenu. This is equivalent to calling
               * popupMenu.getMenuInflater().inflate(menuRes, popupMenu.getMenu()).
               * @param menuRes Menu resource to inflate
               */
              public void inflate(int menuRes) {
                  getMenuInflater().inflate(menuRes, mMenu);
              }
      
              /**
               * Show the menu popup anchored to the view specified during construction.
               * @see #dismiss()
               */
              public void show() {
                  mPopup.show();
              }
      
              /**
               * Dismiss the menu popup.
               * @see #show()
               */
              public void dismiss() {
                  mPopup.dismiss();
              }
      
              /**
               * Set a listener that will be notified when the user selects an item from the menu.
               *
               * @param listener Listener to notify
               */
              public void setOnMenuItemClickListener(OnMenuItemClickListener listener) {
                  mMenuItemClickListener = listener;
              }
      
              /**
               * Set a listener that will be notified when this menu is dismissed.
               *
               * @param listener Listener to notify
               */
              public void setOnDismissListener(OnDismissListener listener) {
                  mDismissListener = listener;
              }
      
              /**
               * @hide
               */
              public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) {
                  if (mMenuItemClickListener != null) {
                      return mMenuItemClickListener.onMenuItemClick(item);
                  }
                  return false;
              }
      
              /**
               * @hide
               */
              public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
                  if (mDismissListener != null) {
                      mDismissListener.onDismiss(this);
                  }
              }
      
              /**
               * @hide
               */
              public boolean onOpenSubMenu(MenuBuilder subMenu) {
                  if (subMenu == null) return false;
      
                  if (!subMenu.hasVisibleItems()) {
                      return true;
                  }
      
                  // Current menu will be dismissed by the normal helper, submenu will be shown in its place.
                  new MenuPopupHelper(mContext, subMenu, mAnchor).show();
                  return true;
              }
      
              /**
               * @hide
               */
              public void onCloseSubMenu(SubMenuBuilder menu) {
              }
      
              /**
               * @hide
               */
              public void onMenuModeChange(MenuBuilder menu) {
              }
      
              /**
               * Interface responsible for receiving menu item click events if the items themselves
               * do not have individual item click listeners.
               */
              public interface OnMenuItemClickListener {
                  /**
                   * This method will be invoked when a menu item is clicked if the item itself did
                   * not already handle the event.
                   *
                   * @param item {@link MenuItem} that was clicked
                   * @return <code>true</code> if the event was handled, <code>false</code> otherwise.
                   */
                  public boolean onMenuItemClick(MenuItem item);
              }
      
      }
      

      来源:https://gist.github.com/mediavrog/9345938

      【讨论】:

      • 我尝试使用这个类并在显示弹出菜单时出现异常。 java.lang.RuntimeException:无法解析索引 6 处的属性
      • 这个类的用法,正如@kevinkl3 在评论中提到的那样:public void showPopup(View v) { IconizedMenu popup = new IconizedMenu(this, v); MenuInflater inflater = popup.getMenuInflater(); inflater.inflate(R.menu.menu_myactivity, popup.getMenu()); popup.show(); }
      【解决方案5】:

      在 popupMenu.show() 之前;使用

      try {
                          Field mFieldPopup=popupMenu.getClass().getDeclaredField("mPopup");
                          mFieldPopup.setAccessible(true);
                          MenuPopupHelper mPopup = (MenuPopupHelper) mFieldPopup.get(popupMenu);
                          mPopup.setForceShowIcon(true);
                      } catch (Exception e) {
      
                      }
      

      【讨论】:

        【解决方案6】:

        这是因为当您使用showAsAction="never" 属性时,默认溢出不会返回您的图标。您可以像这样创建自己的溢出

        <item android:title=""
                android:id="@+id/overflow"
                android:showAsAction="always"
                android:icon="@drawable/overflow_icon">
          <menu >    
            <item android:id="@+id/back"
                  android:icon="@drawable/back1"
                  android:title="Back" />
        
            <item android:id="@+id/My_Profile"
                  android:icon="@drawable/myprofile"
                  android:title="My Profile" />
        
            <item android:id="@+id/Job_Alert"
                  android:icon="@drawable/jobalert4"
                  android:title="Job Alert !" />
        
            <item android:id="@+id/saved_job"
                  android:icon="@drawable/jobapplied"
                  android:title="Saved Job"/>
            <item android:id="@+id/Logout"
                  android:icon="@drawable/logout"
                  android:title="Logout" /> 
          </menu>
        </item>
        

        【讨论】:

          【解决方案7】:

          如果在任何活动中尝试此代码,则将 getbBaseContext() 替换为此,即活动上下文

          PopupMenu popup = new PopupMenu(this, v);
          

          【讨论】:

            【解决方案8】:

            如果你不熟悉反射,你可以使用反射来实现它运行时的方法,在我们的例子中,我们需要在运行时修改 popupMenu 行为,而不是扩展核心类并修改它;)希望有所帮助 试试我的方法就像一个魅力

            private void showPopupMenu(View view) {
                // inflate menu
                PopupMenu popup = new PopupMenu(mcontext, view);
                MenuInflater inflater = popup.getMenuInflater();
                inflater.inflate(R.menu.main, popup.getMenu());
            
                Object menuHelper;
                Class[] argTypes;
                try {
                    Field fMenuHelper = PopupMenu.class.getDeclaredField("mPopup");
                    fMenuHelper.setAccessible(true);
                    menuHelper = fMenuHelper.get(popup);
                    argTypes = new Class[]{boolean.class};
                    menuHelper.getClass().getDeclaredMethod("setForceShowIcon", argTypes).invoke(menuHelper, true);
                } catch (Exception e) {
            
                }
                popup.show();
            
            
            
            
            } 
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多