如何在ActionBar中的溢出菜单中显示图标

问题描述 投票:0回答:18

我知道使用本机 API 是不可能的。有没有解决方法来实现这种视图?

android actionbarsherlock android-actionbar android-menu
18个回答
91
投票

之前发布的答案总体来说还可以。但它基本上删除了溢出菜单的默认行为。诸如在不同的屏幕尺寸上可以显示多少个图标,然后当它们无法显示时它们会掉入溢出菜单之类的事情。通过执行上述操作,您删除了许多重要的功能。

更好的方法是告诉溢出菜单直接显示图标。您可以通过将以下代码添加到您的活动中来完成此操作。

@Override
public boolean onMenuOpened(int featureId, Menu menu)
{
    if(featureId == Window.FEATURE_ACTION_BAR && menu != null){
        if(menu.getClass().getSimpleName().equals("MenuBuilder")){
            try{
                Method m = menu.getClass().getDeclaredMethod(
                    "setOptionalIconsVisible", Boolean.TYPE);
                m.setAccessible(true);
                m.invoke(menu, true);
            }
            catch(NoSuchMethodException e){
                Log.e(TAG, "onMenuOpened", e);
            }
            catch(Exception e){
                throw new RuntimeException(e);
            }
        }
    }
    return super.onMenuOpened(featureId, menu);
}

67
投票

根据之前的答案尝试过此操作,效果很好,至少对于更新版本的支持库(25.1):

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.menu_main, menu);

    if(menu instanceof MenuBuilder){
        MenuBuilder m = (MenuBuilder) menu;
        //noinspection RestrictedApi
        m.setOptionalIconsVisible(true);
    }

    return true;
}

64
投票

在您的菜单 xml 中,使用以下语法来嵌套菜单,您将开始获取带有图标的菜单

<item
    android:id="@+id/empty"
    android:icon="@drawable/ic_action_overflow"
    android:orderInCategory="101"
    android:showAsAction="always">
    <menu>
        <item
            android:id="@+id/action_show_ir_list"
            android:icon="@drawable/ic_menu_friendslist"
            android:showAsAction="always|withText"
            android:title="List"/>
    </menu>
</item>


25
投票

您可以使用 SpannableString

public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.menu_tab, menu);

    MenuItem item = menu.findItem(R.id.action_login);
    SpannableStringBuilder builder = new SpannableStringBuilder("* Login");
    // replace "*" with icon
    builder.setSpan(new ImageSpan(this, R.drawable.login_icon), 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
    item.setTitle(builder);
}

18
投票

Simon 的答案对我来说非常有用,所以我想分享一下我如何将其实现到建议的

onCreateOptionsMenu
方法中:

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu items for use in the action bar
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.main_action_bar, menu);

    // To show icons in the actionbar's overflow menu:
    // http://stackoverflow.com/questions/18374183/how-to-show-icons-in-overflow-menu-in-actionbar
    //if(featureId == Window.FEATURE_ACTION_BAR && menu != null){
        if(menu.getClass().getSimpleName().equals("MenuBuilder")){
            try{
                Method m = menu.getClass().getDeclaredMethod(
                        "setOptionalIconsVisible", Boolean.TYPE);
                m.setAccessible(true);
                m.invoke(menu, true);
            }
            catch(NoSuchMethodException e){
                Log.e(TAG, "onMenuOpened", e);
            }
            catch(Exception e){
                throw new RuntimeException(e);
            }
        }
    //}

    return super.onCreateOptionsMenu(menu);
}

8
投票

基于 @Desmond Lua 的答案,我制作了一个静态方法,用于在下拉列表中使用 XML 中声明的可绘制对象,并确保其着色不会影响常量可绘制状态。 /** * Updates a menu item in the dropdown to show it's icon that was declared in XML. * * @param item * the item to update * @param color * the color to tint with */ private static void updateMenuWithIcon(@NonNull final MenuItem item, final int color) { SpannableStringBuilder builder = new SpannableStringBuilder() .append("*") // the * will be replaced with the icon via ImageSpan .append(" ") // This extra space acts as padding. Adjust as you wish .append(item.getTitle()); // Retrieve the icon that was declared in XML and assigned during inflation if (item.getIcon() != null && item.getIcon().getConstantState() != null) { Drawable drawable = item.getIcon().getConstantState().newDrawable(); // Mutate this drawable so the tint only applies here drawable.mutate().setTint(color); // Needs bounds, or else it won't show up (doesn't know how big to be) drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()); ImageSpan imageSpan = new ImageSpan(drawable); builder.setSpan(imageSpan, 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); item.setTitle(builder); } }

在活动中使用它时,它看起来像这样。根据您的个人需求,这可能会更加优雅。

@Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.menu_activity_provider_connect, menu); int color = ContextCompat.getColor(this, R.color.accent_dark_grey); updateMenuWithIcon(menu.findItem(R.id.email), color); updateMenuWithIcon(menu.findItem(R.id.sms), color); updateMenuWithIcon(menu.findItem(R.id.call), color); return true; }



5
投票
解决方案

可能适用于旧平台。无论如何,在新的 AppCompat21+ 中,所需的方法不存在,并且方法 getDeclaredMethod 返回异常

NoSuchMethodException

所以我的解决方法(在 4.x、5.x 设备上测试和工作)是基于直接更改后台参数。因此,只需将此代码放入您的 Activity 类中即可。

@Override public boolean onMenuOpened(int featureId, Menu menu) { // enable visible icons in action bar if (featureId == Window.FEATURE_ACTION_BAR && menu != null) { if (menu.getClass().getSimpleName().equals("MenuBuilder")) { try { Field field = menu.getClass(). getDeclaredField("mOptionalIconsVisible"); field.setAccessible(true); field.setBoolean(menu, true); } catch (IllegalAccessException | NoSuchFieldException e) { Logger.w(TAG, "onMenuOpened(" + featureId + ", " + menu + ")", e); } } } return super.onMenuOpened(featureId, menu); }



5
投票

public boolean onCreateOptionsMenu(Menu menu){ MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.toolbar_menu,menu); if(menu instanceof MenuBuilder) { //To display icon on overflow menu MenuBuilder m = (MenuBuilder) menu; m.setOptionalIconsVisible(true); } return true; } `



3
投票

@Override protected boolean onPrepareOptionsPanel(View view, Menu menu) { if(menu != null){ if(menu.getClass().getSimpleName().equals("MenuBuilder")){ try{ Method m = menu.getClass().getDeclaredMethod( "setOptionalIconsVisible", Boolean.TYPE); m.setAccessible(true); m.invoke(menu, true); } catch(NoSuchMethodException e){ Log.e(Constants.DEBUG_LOG, "onMenuOpened", e); } catch(Exception e){ throw new RuntimeException(e); } } } return super.onPrepareOptionsPanel(view, menu); }



3
投票

@SuppressLint("RestrictedApi") fun Menu.showOptionalIcons() { this as MenuBuilder setOptionalIconsVisible(true) }



2
投票

@Override public boolean onPrepareActionMode(ActionMode mode, Menu menu) { if(menu != null){ if(menu.getClass().getSimpleName().equals("MenuBuilder")){ try{ Method m = menu.getClass().getDeclaredMethod( "setOptionalIconsVisible", Boolean.TYPE); m.setAccessible(true); m.invoke(menu, true); } catch(NoSuchMethodException e){ Log.e(TAG, "onPrepareActionMode", e); } catch(Exception e){ throw new RuntimeException(e); } } } return true; }



2
投票

<?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_settings" android:icon="@drawable/ic_menu_camera" android:showAsAction="never" android:title="@string/action_settings" /> <item android:id="@+id/action_1" android:icon="@drawable/ic_menu_gallery" android:showAsAction="never" android:title="Hello" /> <item android:id="@+id/action_search" android:icon="@android:drawable/ic_search_category_default" android:showAsAction="never" android:title="action_search"> <menu> <item android:id="@+id/version1" android:icon="@android:drawable/ic_dialog_alert" android:showAsAction="never" android:title="Cup cake" /> <item android:id="@+id/version2" android:icon="@drawable/ic_menu_camera" android:showAsAction="never" android:title="Donut" /> <item android:id="@+id/version3" android:icon="@drawable/ic_menu_send" android:showAsAction="never" android:title="Eclair" /> <item android:id="@+id/version4" android:icon="@drawable/ic_menu_gallery" android:showAsAction="never" android:title="Froyo" /> </menu> </item> </menu>



1
投票
menu.xml


我的答案是动态菜单创建,这是我的代码:

int ACTION_MENU_ID =1; SpannableStringBuilder builder; @Override public boolean onCreateOptionsMenu(Menu menu) { //this space for icon builder = new SpannableStringBuilder(" " + getString(R.string.your_menu_title)); builder.setSpan(new ImageSpan(this, R.drawable.ic_your_menu_icon), 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); //dynamic menu added menu.add(Menu.NONE,ACTION_MENU_ID, Menu.NONE, getString(R.string.your_menu_title)) .setShowAsAction(MenuItemCompat.SHOW_AS_ACTION_WITH_TEXT | MenuItemCompat.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW); //set icon in overflow menu menu.findItem(ACTION_MENU_ID).setTitle(builder); }



1
投票

<menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/action_settings" app:showAsAction="always" android:icon="@drawable/ic_more_vert_white" android:orderInCategory="100" android:title=""> <menu> <item android:id="@+id/Login" android:icon="@drawable/ic_menu_user_icon" android:showAsAction="collapseActionView|withText" android:title="@string/str_Login" /> <item android:id="@+id/str_WishList" android:icon="@drawable/ic_menu_wish_list_icon" android:showAsAction="collapseActionView" android:title="@string/str_WishList" /> <item android:id="@+id/TrackOrder" android:icon="@drawable/ic_menu_my_order_icon" android:showAsAction="collapseActionView" android:title="@string/str_TrackOrder" /> <item android:id="@+id/Ratetheapp" android:icon="@drawable/ic_menu_rate_the_apps" android:showAsAction="collapseActionView" android:title="@string/str_Ratetheapp" /> <item android:id="@+id/Sharetheapp" android:icon="@drawable/ic_menu_shar_the_apps" android:showAsAction="collapseActionView" android:title="@string/str_Sharetheapp" /> <item android:id="@+id/Contactus" android:icon="@drawable/ic_menu_contact" android:showAsAction="collapseActionView" android:title="@string/str_Contactus" /> <item android:id="@+id/Policies" android:icon="@drawable/ic_menu_policy_icon" android:showAsAction="collapseActionView" android:title="@string/str_Policies" /> </menu> </item> </menu>



0
投票


0
投票

<item android:orderInCategory="10" android:title="" android:icon="@drawable/ic_more_vert" app:showAsAction="always" > <menu> <item android:id="@+id/action_tst1" ...and so on </menu> </item>

这会产生“溢出”菜单效果并在下拉列表中显示图标。
如果项目与显示不冲突,甚至可以将项目放在其前面。

我发现 MashukKhan 的解决方案很优雅,它适合解决方案而不是解决方案类别,因为它只是子菜单的实现。


0
投票

日晚和美元空头,但精炼它多一点产量(在 Android 5、10、11 和 12 上测试 - 调试版本):

@Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.menu_X_activity, menu); // All other menus show icons, why leave the overflow menu out? It should match. if(menu instanceof MenuBuilder) { ((MenuBuilder) menu).setOptionalIconsVisible(true); } return super.onCreateOptionsMenu(menu); }



0
投票
每个人都有自己的选择。遗憾的是,onCreateOptionsMenu 已被弃用,现在有更好的方法。这是addMenuProvider方法

public class MainActivity extends AppCompatActivity { private MenuProvider menuProvider; //Please, use this addMenuProvider method in the onResume() lifecycle of your activity. @Override public void onResume() { super.onResume(); if(menuProvider == null) menuProvider = new MenuProvider() { @SuppressLint("RestrictedApi") @Override public void onCreateMenu(@NonNull Menu menu, @NonNull MenuInflater menuInflater) { menuInflater.inflate(R.menu.toolbar_menu, menu); //If you want to add menu items later, then below code is for you. //Else, skip the 4 lines of codes below and continue from the if statement menu.add(0, 1, 0, "First item in overflow menu"); menu.findItem(1).setIcon(R.drawable.my_drawable1); menu.add(0, 2, 0, "Seconditem in overflow menu"); menu.findItem(2).setIcon(R.drawable.my_drawable2); //For Java version 17 & above if (menu instanceof MenuBuilder menuBuilder) { menuBuilder.setOptionalIconsVisible(true); } } @Override public boolean onMenuItemSelected(@NonNull MenuItem menuItem) { return true; } }; MainActivity.this.addMenuProvider(menuProvider, MainActivity.this, Lifecycle.State.RESUMED); @Override public void onPause() { //To avoid duplicates, please remove the menu items in the onPause method if (menuProvider != null) { MainActivity.this.removeMenuProvider(menuProvider); menuProvider = null; } } }

我使用这种编码技术是因为 Android 操作系统可以决定销毁你的 Activity 而无需调用 onDestroy 方法

© www.soinside.com 2019 - 2024. All rights reserved.