web-dev-qa-db-fra.com

Comment afficher des icônes dans le menu Débordement dans ActionBar

Je sais que ce n'est pas possible en utilisant l'API native. Existe-t-il une solution de contournement pour mettre en œuvre ce type de vue?

62
Mihir

La réponse précédemment affichée est OK, en général. Mais cela supprime fondamentalement le comportement par défaut du menu Dépassement. Des éléments tels que le nombre d'icônes pouvant être affichées sur différentes tailles d'écran, puis insérées dans le menu de débordement lorsqu'elles ne peuvent pas être affichées. En faisant ce qui précède, vous supprimez de nombreuses fonctionnalités importantes.

Une meilleure méthode consisterait à indiquer au menu de débordement d’afficher directement les icônes. Vous pouvez le faire en ajoutant le code suivant à votre activité.

@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

Dans votre menu XML, utilisez la syntaxe suivante pour imbriquer le menu, vous commencerez à obtenir le menu avec des icônes

<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

Essayé en me basant sur les réponses précédentes et cela fonctionne bien, du moins avec les versions les plus récentes de la bibliothèque de support (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

Vous pouvez utiliser 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

La réponse de Simon m'a été très utile, je souhaite donc partager comment je l'ai implémentée dans la méthode onCreateOptionsMenu- comme suggéré:

@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

En me basant sur la réponse de @Desmond Lua de ci-dessus , j'ai créé une méthode statique pour utiliser le dessinable déclaré en XML dans la liste déroulante, et en veillant à ce que sa couleur teintée n'affecte pas l'état de Dessin constant.

    /**
 * 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);
    }
}

Et l’utiliser ressemblerait à quelque chose comme ceci lorsqu’il est utilisé dans une activité. Cela pourrait probablement être encore plus élégant en fonction de vos besoins.

@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

La réponse de @Simon fonctionne vraiment bien ... mais vous utilisez AppCompat Activity ... vous devrez utiliser ce code à la place ... car onMenuOpened () n'est plus appelé dans 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

Le meilleur actuel, mais non accepté solution fonctionne probablement sur les anciennes plates-formes. Quoi qu'il en soit, dans la nouvelle AppCompat21 +, la méthode requise n'existe pas et la méthode getDeclaredMethod renvoie l'exception NoSuchMethodException.

Donc, la solution de contournement pour moi (testé et fonctionnant sur des périphériques 4.x, 5.x) est basée sur le paramètre de fond de changement direct. Il suffit donc de placer ce code dans votre classe d’activité.

@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

La façon la plus simple que j'ai trouvée est la suivante:

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

Selon moi, cela n'est possible qu'en créant une barre d'outils personnalisée. Parce que ActionBar par défaut ne vous donne pas cette fonctionnalité. Mais vous pouvez mettre des icônes en prenant le sous-menu en tant qu'enfant d'un élément. Et si vous avez une meilleure solution que moi… informez-moi simplement.

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

Mon simple mod à l'excellente solution de Simon à utiliser avec ActionMode:

 @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

C'est trop tard, mais quelqu'un peut m'aider. J'ai reçu l'aide de @Desmond Lua qui aide pour qui utilise menu.xml

Ma réponse est pour la création de menu dynamique, voici mon code:

  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

Ajoutez ceci en style:

<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