Dies ist eindeutig ein Problem, das viele Programmierer haben und für das Google noch keine zufriedenstellende, unterstützte Lösung bereitstellen muss.
Es gibt viele gekreuzte Absichten und Missverständnisse in den Beiträgen zu diesem Thema. Lesen Sie daher bitte die gesamte Antwort, bevor Sie antworten.
Im Folgenden füge ich eine "verfeinerte" und gut kommentierte Version des Hacks aus anderen Antworten auf dieser Seite hinzu, die auch Ideen aus diesen sehr eng verwandten Fragen enthält:
Ändern Sie die Hintergrundfarbe des Android-Menüs
Wie ändere ich die Hintergrundfarbe des Optionsmenüs?
Android: Menü der Anwendung anpassen (z. B. Hintergrundfarbe)
http://www.macadamian.com/blog/post/android_-_theming_the_unthemable/
Android MenuItem Umschalttaste
Ist es möglich, den Hintergrund des Android-Optionsmenüs nicht durchscheinend zu machen?
http://www.codeproject.com/KB/android/AndroidMenusMyWay.aspx
Einstellen des Menühintergrunds auf undurchsichtig
Ich habe diesen Hack auf 2.1 (Simulator), 2.2 (2 echte Geräte) und 2.3 (2 echte Geräte) getestet. Ich habe noch keine 3.X-Tablets zum Testen, werde aber alle erforderlichen Änderungen hier veröffentlichen, wenn / falls ich dies tue. Angesichts der Tatsache, dass 3.X-Tablets Aktionsleisten anstelle von Optionsmenüs verwenden, wie hier erläutert:
http://developer.android.com/guide/topics/ui/menus.html#options-menu
Dieser Hack wird mit ziemlicher Sicherheit nichts (kein Schaden und kein Nutzen) auf 3.X-Tablets bewirken.
STELLUNGNAHME DES PROBLEMS (lesen Sie dies, bevor Sie mit einem negativen Kommentar auf den Auslöser antworten):
Das Optionsmenü hat auf verschiedenen Geräten sehr unterschiedliche Stile. Reines Schwarz mit weißem Text auf einigen, reines Weiß mit schwarzem Text auf einigen. Ich und viele andere Entwickler möchten die Hintergrundfarbe der Optionsmenüzellen sowie die Farbe des Optionsmenütextes steuern .
Bestimmte App-Entwickler müssen nur die Hintergrundfarbe der Zelle festlegen (nicht die Textfarbe), und dies können sie mit dem in einer anderen Antwort beschriebenen android: panelFullBackground-Stil sauberer tun. Derzeit gibt es jedoch keine Möglichkeit, die Textfarbe des Optionsmenüs mit Stilen zu steuern. Daher kann diese Methode nur verwendet werden, um den Hintergrund in eine andere Farbe zu ändern, die den Text nicht "verschwinden" lässt.
Wir würden dies gerne mit einer dokumentierten, zukunftssicheren Lösung tun, aber eine ist ab Android <= 2.3 einfach nicht verfügbar. Daher müssen wir eine Lösung verwenden, die in aktuellen Versionen funktioniert und die Wahrscheinlichkeit eines Absturzes / Bruches in zukünftigen Versionen minimiert. Wir wollen eine Lösung, die ordnungsgemäß zum Standardverhalten zurückfällt, wenn sie fehlschlagen muss.
Es gibt viele legitime Gründe, warum man möglicherweise das Aussehen von Optionsmenüs steuern muss (normalerweise, um einem visuellen Stil für den Rest der App zu entsprechen), damit ich nicht weiter darauf eingehen werde.
Es gibt einen Google Android-Fehler, der dazu gepostet wurde: Bitte fügen Sie Ihre Unterstützung hinzu, indem Sie diesen Fehler markieren (Hinweis: Google rät von "Ich auch" -Kommentaren ab: Nur ein Stern ist genug):
http://code.google.com/p/android/issues/detail?id=4441
ZUSAMMENFASSUNG DER LÖSUNGEN Bisher:
Mehrere Poster haben einen Hack mit LayoutInflater.Factory vorgeschlagen. Der vorgeschlagene Hack funktionierte für Android <= 2.2 und schlug für Android 2.3 fehl, da der Hack eine undokumentierte Annahme machte: Man könnte LayoutInflater.getView () direkt aufrufen, ohne sich derzeit in einem Aufruf von LayoutInflater.inflate () auf derselben LayoutInflater-Instanz zu befinden. Neuer Code in Android 2.3 hat diese Annahme gebrochen und zu einer NullPointerException geführt.
Mein leicht verfeinerter Hack unten beruht nicht auf dieser Annahme.
Darüber hinaus basieren die Hacks auch auf der Verwendung eines internen, nicht dokumentierten Klassennamens "com.android.internal.view.menu.IconMenuItemView" als Zeichenfolge (nicht als Java-Typ). Ich sehe keinen Weg, dies zu vermeiden und trotzdem das erklärte Ziel zu erreichen. Es ist jedoch möglich, den Hack auf eine vorsichtige Weise durchzuführen, die zurückfällt, wenn "com.android.internal.view.menu.IconMenuItemView" auf dem aktuellen System nicht angezeigt wird.
Verstehe wieder, dass dies ein Hack ist und ich behaupte keineswegs, dass dies auf allen Plattformen funktionieren wird. Aber wir Entwickler leben nicht in einer akademischen Fantasy-Welt, in der alles nach dem Buch sein muss: Wir haben ein Problem zu lösen und wir müssen es so gut wie möglich lösen. Beispielsweise ist es unwahrscheinlich, dass "com.android.internal.view.menu.IconMenuItemView" auf 3.X-Tablets vorhanden ist, da sie Aktionsleisten anstelle von Optionsmenüs verwenden.
Schließlich haben einige Entwickler dieses Problem gelöst, indem sie das Android-Optionsmenü vollständig unterdrückt und ihre eigene Menüklasse geschrieben haben (siehe einige der obigen Links). Ich habe das noch nicht ausprobiert, aber wenn Sie Zeit haben, Ihre eigene Ansicht zu schreiben und herauszufinden, wie Sie die Ansicht von Android ersetzen können (ich bin sicher, der Teufel steckt hier im Detail), ist dies möglicherweise eine nette Lösung, für die keine erforderlich ist undokumentierte Hacks.
HACKEN:
Hier ist der Code.
Um diesen Code zu verwenden, rufen Sie addOptionsMenuHackerInflaterFactory () EINMAL von Ihrer Aktivität onCreate () oder Ihrer Aktivität onCreateOptionsMenu () auf. Es wird eine Standardfactory festgelegt, die sich auf die spätere Erstellung eines Optionsmenüs auswirkt. Es hat keine Auswirkungen auf bereits erstellte Optionsmenüs (die vorherigen Hacks verwendeten den Funktionsnamen setMenuBackground (), was sehr irreführend ist, da die Funktion vor ihrer Rückkehr keine Menüeigenschaften festlegt).
@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;
}
});
}
Danke fürs Lesen und viel Spaß!