Este es claramente un problema que tienen muchos programadores y al que Google aún no ha proporcionado una solución satisfactoria y compatible.
Hay muchas intenciones cruzadas y malentendidos flotando alrededor de las publicaciones sobre este tema, así que lea esta respuesta completa antes de responder.
A continuación incluyo una versión más "refinada" y bien comentada del truco de otras respuestas en esta página, que también incorpora ideas de estas preguntas muy relacionadas:
Cambiar el color de fondo del menú de Android
¿Cómo cambiar el color de fondo del menú de opciones?
Android: personaliza el menú de la aplicación (por ejemplo, color de fondo)
http://www.macadamian.com/blog/post/android_-_theming_the_unthemable/
Menú de Android Botón de alternancia de elementos
¿Es posible hacer que el fondo del menú de opciones de Android no sea translúcido?
http://www.codeproject.com/KB/android/AndroidMenusMyWay.aspx
Configurar el fondo del menú para que sea opaco
Probé este truco en 2.1 (simulador), 2.2 (2 dispositivos reales) y 2.3 (2 dispositivos reales). No tengo ninguna tableta 3.X para probar todavía, pero publicaré los cambios necesarios aquí cuando o si los tengo. Dado que las tabletas 3.X usan barras de acción en lugar de menús de opciones, como se explica aquí:
http://developer.android.com/guide/topics/ui/menus.html#options-menu
Es casi seguro que este truco no hará nada (ni daño ni beneficio) en tabletas 3.X.
EXPOSICIÓN DEL PROBLEMA (lea esto antes de disparar-responder con un comentario negativo):
El menú Opciones tiene estilos muy diferentes en diferentes dispositivos. Negro puro con texto blanco en algunos, blanco puro con texto negro en algunos. Yo y muchos otros desarrolladores deseamos controlar el color de fondo de las celdas del menú Opciones , así como el color del texto del menú Opciones .
Algunos desarrolladores de aplicaciones solo necesitan establecer el color de fondo de la celda (no el color del texto), y pueden hacerlo de una manera más limpia usando el estilo android: panelFullBackground descrito en otra respuesta. Sin embargo, actualmente no hay forma de controlar el color del texto del menú Opciones con estilos, por lo que solo se puede usar este método para cambiar el fondo a otro color que no haga que el texto "desaparezca".
Nos encantaría hacer esto con una solución documentada y preparada para el futuro, pero simplemente no hay una disponible a partir de Android <= 2.3. Por lo tanto, tenemos que usar una solución que funcione en las versiones actuales y que esté diseñada para minimizar las posibilidades de fallar o romperse en versiones futuras. Queremos una solución que vuelva a fallar con gracia al comportamiento predeterminado si tiene que fallar.
Hay muchas razones legítimas por las que uno puede necesitar controlar el aspecto de los menús de Opciones (generalmente para que coincida con un estilo visual para el resto de la aplicación), así que no me detendré en eso.
Hay un error de Google Android publicado sobre esto: agregue su apoyo destacando este error (tenga en cuenta que Google desalienta los comentarios de "yo también": solo una estrella es suficiente):
http://code.google.com/p/android/issues/detail?id=4441
RESUMEN DE SOLUCIONES HASTA AHORA:
Varios carteles han sugerido un truco relacionado con LayoutInflater.Factory. El truco sugerido funcionó para Android <= 2.2 y falló para Android 2.3 porque el truco hizo una suposición no documentada: que uno podría llamar a LayoutInflater.getView () directamente sin estar actualmente dentro de una llamada a LayoutInflater.inflate () en la misma instancia de LayoutInflater. El nuevo código en Android 2.3 rompió esta suposición y condujo a una NullPointerException.
Mi truco ligeramente refinado a continuación no se basa en esta suposición.
Además, los hacks también se basan en el uso de un nombre de clase interno no documentado "com.android.internal.view.menu.IconMenuItemView" como una cadena (no como un tipo Java). No veo ninguna forma de evitar esto y aún así lograr el objetivo establecido. Sin embargo, es posible hacer el truco de una manera cuidadosa que retroceda si "com.android.internal.view.menu.IconMenuItemView" no aparece en el sistema actual.
Nuevamente, entienda que esto es un truco y de ninguna manera estoy afirmando que esto funcionará en todas las plataformas. Pero los desarrolladores no vivimos en un mundo académico de fantasía donde todo tiene que ser según las reglas: tenemos un problema que resolver y tenemos que resolverlo lo mejor que podamos. Por ejemplo, parece poco probable que "com.android.internal.view.menu.IconMenuItemView" exista en tabletas 3.X ya que utilizan barras de acción en lugar de menús de opciones.
Finalmente, algunos desarrolladores han resuelto este problema suprimiendo totalmente el menú de opciones de Android y escribiendo su propia clase de menú (consulte algunos de los enlaces anteriores). No he probado esto, pero si tiene tiempo para escribir su propia Vista y descubrir cómo reemplazar la vista de Android (estoy seguro de que el diablo está en los detalles aquí), entonces podría ser una buena solución que no requiere ninguna hacks indocumentados.
CORTAR A TAJOS:
Aquí está el código.
Para usar este código, llame a addOptionsMenuHackerInflaterFactory () UNA VEZ desde su actividad enCreate () o su actividad enCreateOptionsMenu (). Establece una fábrica predeterminada que afectará la creación posterior de cualquier menú de opciones. No afecta los menús de opciones que ya se han creado (los hacks anteriores usaban un nombre de función de setMenuBackground (), que es muy engañoso ya que la función no establece ninguna propiedad de menú antes de regresar).
@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;
}
});
}
¡Gracias por leer y disfrutar!