Jest to wyraźnie problem, który ma wielu programistów i któremu Google jeszcze nie zapewniło satysfakcjonującego, obsługiwanego rozwiązania.
Wokół postów na ten temat krąży wiele krzyżujących się intencji i nieporozumień, dlatego przed udzieleniem odpowiedzi prosimy o przeczytanie całej odpowiedzi.
Poniżej zamieszczam bardziej „dopracowaną” i dobrze skomentowaną wersję hackowania z innych odpowiedzi na tej stronie, zawierającą również pomysły z tych bardzo ściśle powiązanych pytań:
Zmień kolor tła menu Androida
Jak zmienić kolor tła menu opcji?
Android: dostosuj menu aplikacji (np. Kolor tła)
http://www.macadamian.com/blog/post/android_-_theming_the_unthemable/
Przycisk przełącznika elementu menu Android
Czy można ustawić nieprzezroczyste tło menu opcji Androida?
http://www.codeproject.com/KB/android/AndroidMenusMyWay.aspx
Ustawianie nieprzezroczystego tła menu
Przetestowałem ten hack na 2.1 (symulator), 2.2 (2 prawdziwe urządzenia) i 2.3 (2 prawdziwe urządzenia). Nie mam jeszcze żadnych tabletów 3.X do przetestowania, ale opublikuję tutaj wszelkie potrzebne zmiany, kiedy / jeśli to zrobię. Biorąc pod uwagę, że tablety 3.X używają pasków akcji zamiast menu opcji, jak wyjaśniono tutaj:
http://developer.android.com/guide/topics/ui/menus.html#options-menu
ten hack prawie na pewno nic nie da (nic złego i nic dobrego) na tabletach 3.X.
OPIS PROBLEMU (przeczytaj to przed odpowiedzią wyzwalającą z negatywnym komentarzem):
Menu Opcje ma bardzo różne style na różnych urządzeniach. Czysta czerń z białym tekstem na niektórych, czysta biel z czarnym tekstem na niektórych. Ja i wielu innych programistów chcemy kontrolować kolor tła komórek menu Opcje, a także kolor tekstu menu Opcje .
Niektórzy programiści aplikacji muszą tylko ustawić kolor tła komórki (nie kolor tekstu) i mogą to zrobić w bardziej przejrzysty sposób, korzystając ze stylu android: panelFullBackground opisanego w innej odpowiedzi. Jednak obecnie nie ma możliwości kontrolowania koloru tekstu w menu Opcje za pomocą stylów, więc można użyć tej metody tylko do zmiany koloru tła na inny, który nie spowoduje „zniknięcia” tekstu.
Chcielibyśmy to zrobić za pomocą udokumentowanego, przyszłościowego rozwiązania, ale jedno z nich jest po prostu niedostępne w systemie Android <= 2.3. Musimy więc użyć rozwiązania, które działa w aktualnych wersjach i jest zaprojektowane tak, aby zminimalizować ryzyko awarii / zepsucia w przyszłych wersjach. Chcemy rozwiązania, które wdzięcznie zawiedzie i przywróci domyślne zachowanie, jeśli musi zawieść.
Istnieje wiele uzasadnionych powodów, dla których może być konieczne kontrolowanie wyglądu menu opcji (zazwyczaj w celu dopasowania stylu wizualnego do reszty aplikacji), więc nie będę się nad tym rozwodzić.
Jest opublikowany błąd Google Android na ten temat: dodaj swoje wsparcie, oznaczając ten błąd gwiazdką (pamiętaj, że Google odradza komentarze „ja też”: wystarczy gwiazdka):
http://code.google.com/p/android/issues/detail?id=4441
PODSUMOWANIE DOTYCHCZASOWYCH ROZWIĄZAŃ:
Kilka plakatów sugerowało włamanie do LayoutInflater.Factory. Sugerowany hack działał dla Androida <= 2.2 i nie powiódł się dla Androida 2.3, ponieważ hack przyjął nieudokumentowane założenie: można wywołać LayoutInflater.getView () bezpośrednio, bez bieżącego wywoływania LayoutInflater.inflate () w tej samej instancji LayoutInflater. Nowy kod w systemie Android 2.3 złamał to założenie i doprowadził do wyjątku NullPointerException.
Mój nieco dopracowany hack poniżej nie opiera się na tym założeniu.
Co więcej, ataki polegają również na użyciu wewnętrznej, nieudokumentowanej nazwy klasy „com.android.internal.view.menu.IconMenuItemView” jako ciągu znaków (a nie typu Java). Nie widzę sposobu, aby tego uniknąć i nadal osiągać wyznaczony cel. Możliwe jest jednak ostrożne włamanie, które może się cofnąć, jeśli „com.android.internal.view.menu.IconMenuItemView” nie pojawi się w bieżącym systemie.
Ponownie, zrozum, że to hack i w żadnym wypadku nie twierdzę, że będzie działać na wszystkich platformach. Ale my, programiści, nie żyjemy w fantastycznym świecie akademickim, w którym wszystko musi być zgodne z książką: mamy problem do rozwiązania i musimy go rozwiązać najlepiej, jak potrafimy. Na przykład wydaje się mało prawdopodobne, że „com.android.internal.view.menu.IconMenuItemView” będzie istnieć na tabletach 3.X, ponieważ używają one pasków akcji zamiast menu opcji.
Wreszcie, niektórzy programiści rozwiązali ten problem, całkowicie pomijając menu opcji Androida i pisząc własną klasę menu (zobacz niektóre z linków powyżej). Nie próbowałem tego, ale jeśli masz czas na napisanie własnego widoku i wymyślenie, jak zastąpić widok Androida (jestem pewien, że diabeł tkwi tutaj w szczegółach), może to być fajne rozwiązanie, które nie wymaga żadnego nieudokumentowane hacki.
WŁAMAĆ SIĘ:
Oto kod.
Aby użyć tego kodu, wywołaj addOptionsMenuHackerInflaterFactory () RAZ w swojej aktywności onCreate () lub swojej aktywności onCreateOptionsMenu (). Ustawia domyślną fabrykę, która wpłynie na późniejsze tworzenie dowolnego menu opcji. Nie ma to wpływu na menu opcji, które zostały już utworzone (poprzednie hacki używały nazwy funkcji setMenuBackground (), co jest bardzo mylące, ponieważ funkcja nie ustawia żadnych właściwości menu przed powrotem).
@SuppressWarnings("rawtypes")
static Class IconMenuItemView_class = null;
@SuppressWarnings("rawtypes")
static Constructor IconMenuItemView_constructor = null;
@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;
View view = null;
if (IconMenuItemView_class == null)
{
try
{
IconMenuItemView_class = getClassLoader().loadClass(name);
}
catch (ClassNotFoundException e)
{
return null;
}
}
if (IconMenuItemView_class == null)
return null;
if (IconMenuItemView_constructor == null)
{
try
{
IconMenuItemView_constructor =
IconMenuItemView_class.getConstructor(standard_inflater_constructor_signature);
}
catch (SecurityException e)
{
return null;
}
catch (NoSuchMethodException e)
{
return null;
}
}
if (IconMenuItemView_constructor == null)
return null;
try
{
Object[] args = new Object[] { context, attrs };
view = (View)(IconMenuItemView_constructor.newInstance(args));
}
catch (IllegalArgumentException e)
{
return null;
}
catch (InstantiationException e)
{
return null;
}
catch (IllegalAccessException e)
{
return null;
}
catch (InvocationTargetException e)
{
return null;
}
if (null == view)
return null;
final View v = view;
new Handler().post(new Runnable()
{
public void run()
{
v.setBackgroundColor(Color.BLACK);
try
{
TextView tv = (TextView)v;
tv.setTextColor(Color.WHITE);
}
catch (ClassCastException e)
{
}
}
});
return view;
}
});
}
Dziękuję za przeczytanie i miłej zabawy!