C'est clairement un problème rencontré par de nombreux programmeurs et auquel Google n'a pas encore fourni de solution satisfaisante et prise en charge.
Il y a beaucoup d'intentions croisées et de malentendus flottant autour des articles sur ce sujet, alors veuillez lire toute cette réponse avant de répondre.
Ci-dessous, j'inclus une version plus "raffinée" et bien commentée du hack d'autres réponses sur cette page, incorporant également des idées de ces questions très étroitement liées:
Changer la couleur d'arrière-plan du menu Android
Comment changer la couleur de fond du menu d'options?
Android: personnaliser le menu de l'application (par exemple, la couleur de fond)
http://www.macadamian.com/blog/post/android_-_theming_the_unthemable/
Bouton Android Menu
Est-il possible de rendre l'arrière-plan du menu des options Android non translucide?
http://www.codeproject.com/KB/android/AndroidMenusMyWay.aspx
Définition de l'arrière-plan du menu pour être opaque
J'ai testé ce hack sur 2.1 (simulateur), 2.2 (2 vrais appareils) et 2.3 (2 vrais appareils). Je n'ai pas encore de tablette 3.X à tester, mais je publierai les modifications nécessaires ici si / si je le fais. Étant donné que les tablettes 3.X utilisent des barres d'action au lieu des menus d'options, comme expliqué ici:
http://developer.android.com/guide/topics/ui/menus.html#options-menu
ce hack ne fera presque certainement rien (ni mal ni bon) sur les tablettes 3.X.
ÉNONCÉ DU PROBLÈME (lisez ceci avant de répondre au déclencheur avec un commentaire négatif):
Le menu Options a des styles très différents sur différents appareils. Noir pur avec du texte blanc sur certains, blanc pur avec du texte noir sur certains. Moi-même et de nombreux autres développeurs souhaitons contrôler la couleur d'arrière-plan des cellules du menu Options ainsi que la couleur du texte du menu Options .
Certains développeurs d'applications n'ont besoin que de définir la couleur d'arrière-plan de la cellule (pas la couleur du texte), et ils peuvent le faire de manière plus propre en utilisant le style android: panelFullBackground décrit dans une autre réponse. Cependant, il n'existe actuellement aucun moyen de contrôler la couleur du texte du menu Options avec des styles, et on ne peut donc utiliser cette méthode que pour changer l'arrière-plan en une autre couleur qui ne fera pas «disparaître» le texte.
Nous serions ravis de le faire avec une solution documentée et pérenne, mais l'une d'entre elles n'est tout simplement pas disponible à partir d'Android <= 2.3. Nous devons donc utiliser une solution qui fonctionne dans les versions actuelles et qui est conçue pour minimiser les risques de plantage / rupture dans les versions futures. Nous voulons une solution qui échoue correctement au comportement par défaut si elle doit échouer.
Il existe de nombreuses raisons légitimes pour lesquelles il peut être nécessaire de contrôler l'apparence des menus d'options (généralement pour correspondre à un style visuel pour le reste de l'application), je ne m'attarderai donc pas là-dessus.
Il y a un bug Google Android à ce sujet: veuillez ajouter votre soutien en mettant en vedette ce bug (notez que Google décourage les commentaires "moi aussi": juste une étoile suffit):
http://code.google.com/p/android/issues/detail?id=4441
RÉSUMÉ DES SOLUTIONS À CE JOUR:
Plusieurs affiches ont suggéré un hack impliquant LayoutInflater.Factory. Le piratage suggéré a fonctionné pour Android <= 2.2 et a échoué pour Android 2.3 parce que le piratage a fait une hypothèse non documentée: qu'on pourrait appeler LayoutInflater.getView () directement sans être actuellement dans un appel à LayoutInflater.inflate () sur la même instance de LayoutInflater. Le nouveau code dans Android 2.3 a cassé cette hypothèse et a conduit à une NullPointerException.
Mon hack légèrement raffiné ci-dessous ne repose pas sur cette hypothèse.
En outre, les hacks reposent également sur l'utilisation d'un nom de classe interne non documenté "com.android.internal.view.menu.IconMenuItemView" en tant que chaîne (pas en tant que type Java). Je ne vois aucun moyen d'éviter cela et d'atteindre toujours l'objectif déclaré. Cependant, il est possible de faire le piratage d'une manière prudente qui se rabattra si "com.android.internal.view.menu.IconMenuItemView" n'apparaît pas sur le système actuel.
Encore une fois, comprenez qu'il s'agit d'un hack et je ne prétends en aucun cas que cela fonctionnera sur toutes les plates-formes. Mais nous, les développeurs, ne vivons pas dans un monde académique fantastique où tout doit être écrit: nous avons un problème à résoudre et nous devons le résoudre du mieux que nous pouvons. Par exemple, il semble peu probable que "com.android.internal.view.menu.IconMenuItemView" existe sur les tablettes 3.X car elles utilisent des barres d'action au lieu des menus d'options.
Enfin, certains développeurs ont résolu ce problème en supprimant totalement le menu d'options Android et en écrivant leur propre classe de menu (voir certains des liens ci-dessus). Je n'ai pas essayé cela, mais si vous avez le temps d'écrire votre propre vue et de trouver comment remplacer la vue d'Android (je suis sûr que le diable est dans les détails ici), alors cela pourrait être une bonne solution qui ne nécessite aucun hacks non documentés.
PIRATER:
Voici le code.
Pour utiliser ce code, appelez addOptionsMenuHackerInflaterFactory () UNE FOIS depuis votre activité onCreate () ou votre activité onCreateOptionsMenu (). Il définit une usine par défaut qui affectera la création ultérieure de tout menu d'options. Cela n'affecte pas les menus d'options qui ont déjà été créés (les hacks précédents utilisaient un nom de fonction de setMenuBackground (), ce qui est très trompeur car la fonction ne définit aucune propriété de menu avant son retour).
@SuppressWarnings("rawtypes")
static Class IconMenuItemView_class = null;
@SuppressWarnings("rawtypes")
static Constructor IconMenuItemView_constructor = null;
// standard signature of constructor expected by inflater of all View classes
@SuppressWarnings("rawtypes")
private static final Class[] standard_inflater_constructor_signature =
new Class[] { Context.class, AttributeSet.class };
protected void addOptionsMenuHackerInflaterFactory()
{
final LayoutInflater infl = getLayoutInflater();
infl.setFactory(new Factory()
{
public View onCreateView(final String name,
final Context context,
final AttributeSet attrs)
{
if (!name.equalsIgnoreCase("com.android.internal.view.menu.IconMenuItemView"))
return null; // use normal inflater
View view = null;
// "com.android.internal.view.menu.IconMenuItemView"
// - is the name of an internal Java class
// - that exists in Android <= 3.2 and possibly beyond
// - that may or may not exist in other Android revs
// - is the class whose instance we want to modify to set background etc.
// - is the class we want to instantiate with the standard constructor:
// IconMenuItemView(context, attrs)
// - this is what the LayoutInflater does if we return null
// - unfortunately we cannot just call:
// infl.createView(name, null, attrs);
// here because on Android 3.2 (and possibly later):
// 1. createView() can only be called inside inflate(),
// because inflate() sets the context parameter ultimately
// passed to the IconMenuItemView constructor's first arg,
// storing it in a LayoutInflater instance variable.
// 2. we are inside inflate(),
// 3. BUT from a different instance of LayoutInflater (not infl)
// 4. there is no way to get access to the actual instance being used
// - so we must do what createView() would have done for us
//
if (IconMenuItemView_class == null)
{
try
{
IconMenuItemView_class = getClassLoader().loadClass(name);
}
catch (ClassNotFoundException e)
{
// this OS does not have IconMenuItemView - fail gracefully
return null; // hack failed: use normal inflater
}
}
if (IconMenuItemView_class == null)
return null; // hack failed: use normal inflater
if (IconMenuItemView_constructor == null)
{
try
{
IconMenuItemView_constructor =
IconMenuItemView_class.getConstructor(standard_inflater_constructor_signature);
}
catch (SecurityException e)
{
return null; // hack failed: use normal inflater
}
catch (NoSuchMethodException e)
{
return null; // hack failed: use normal inflater
}
}
if (IconMenuItemView_constructor == null)
return null; // hack failed: use normal inflater
try
{
Object[] args = new Object[] { context, attrs };
view = (View)(IconMenuItemView_constructor.newInstance(args));
}
catch (IllegalArgumentException e)
{
return null; // hack failed: use normal inflater
}
catch (InstantiationException e)
{
return null; // hack failed: use normal inflater
}
catch (IllegalAccessException e)
{
return null; // hack failed: use normal inflater
}
catch (InvocationTargetException e)
{
return null; // hack failed: use normal inflater
}
if (null == view) // in theory handled above, but be safe...
return null; // hack failed: use normal inflater
// apply our own View settings after we get back to runloop
// - android will overwrite almost any setting we make now
final View v = view;
new Handler().post(new Runnable()
{
public void run()
{
v.setBackgroundColor(Color.BLACK);
try
{
// in Android <= 3.2, IconMenuItemView implemented with TextView
// guard against possible future change in implementation
TextView tv = (TextView)v;
tv.setTextColor(Color.WHITE);
}
catch (ClassCastException e)
{
// hack failed: do not set TextView attributes
}
}
});
return view;
}
});
}
Merci d'avoir lu et amusez-vous!