web-dev-qa-db-ja.com

ActionBarのオーバーフローメニューにアイコンを表示する方法

ネイティブAPIを使用することはできません。そのようなビューを実装する回避策はありますか?

62
Mihir

以前に投稿された回答は、一般的に言えばOKです。ただし、基本的にはオーバーフローメニューのデフォルトの動作は削除されます。さまざまな画面サイズで表示できるアイコンの数、および表示できないときにオーバーフローメニューにドロップされるアイコンの数など。上記を行うことで、多くの重要な機能を削除します。

より良い方法は、オーバーフローメニューにアイコンを直接表示するように指示することです。これを行うには、アクティビティに次のコードを追加します。

@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);
}
84
Simon

メニュー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>
53
iBabur

以前の回答に基づいてこれを試してみましたが、少なくとも最新バージョンのサポートライブラリ(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;
}
38
lbarbosa

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);
}
22
Desmond Lua

サイモンからの答えは私にとって非常に有用だったので、提案されたonCreateOptionsMenu- methodへの実装方法を共有したいと思います。

@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);
}
13
user2366975

上記 からの@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;
}
7
Kevin Grant

@Simonの答えは本当にうまくいきます...しかし、あなたはAppCompatアクティビティを使用しています...代わりにこのコードを使用する必要があります... onMenuOpened()はappcompat-v7:22.xではもう呼び出されないためです

@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
Vishal Kumar

現在のところ最高ですが、受け入れられません ソリューション はおそらく古いプラットフォームで動作します。とにかく新しい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);
}
3
Menion Asamm

私が見つけた最も簡単な方法はこれです:

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;
}        `
2
Paras Singh

私によると、これはカスタムツールバーを作成することによってのみ可能です。デフォルトのActionBarではその機能が提供されないためです。ただし、サブメニューをアイテムの子として使用してアイコンを配置できます。そして、あなたが私よりも良い解決策を持っているなら..私に知らせてください。

<?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> 
2
MashukKhan

ActionModeで使用するSimonの優れたソリューションに対する私の簡単なmod:

 @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
Kaamel

これは遅すぎますが、誰かが_menu.xml_を使用している人に役立つ@Desmond Luaの回答から助けを得たかもしれません

私の答えは、動的なメニュー作成のためのコードです:

_  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
MilapTank

これをスタイルで追加します。

<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>
1
Dashrath Rathod
 public void showContextMenuIconVisible(Menu menu){
    if (menu.getClass().getSimpleName().equals("MenuBuilder")) {
        try {
            Field field = menu.getClass().getDeclaredField("mOptionalIconsVisible");
            field.setAccessible(true);
            field.setBoolean(menu, true);
        } catch (Exception ignored) {
            ignored.printStackTrace();
        }
    }
}
0
chry