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