Очевидно, що це проблема, яку має багато програмістів і для якої Google ще не запропонував задовільного рішення, що підтримується.
Багато перехрещених намірів та непорозумінь плаває навколо дописів на цю тему, тому, будь ласка, прочитайте всю цю відповідь перед тим, як відповісти.
Нижче я включаю більш "вишукану" та добре коментовану версію рубанки з інших відповідей на цій сторінці, також включаючи ідеї з цих дуже тісно пов'язаних питань:
Змінити колір фону меню Android
Як змінити колір тла меню параметрів?
Android: налаштуйте меню програми (наприклад, колір тла)
http://www.macadamian.com/blog/post/android_-_theming_the_unthemable/
Кнопка перемикання меню в меню Android
Чи можна зробити фон меню параметрів Android непрозорим?
http://www.codeproject.com/KB/android/AndroidMenusMyWay.aspx
Встановлення непрозорого фону меню
Я протестував цей хак на 2.1 (симулятор), 2.2 (2 реальних пристрої) та 2.3 (2 реальних пристрої). У мене ще немає планшетів 3.X для тестування, але тут, коли / якщо я, буду розміщувати тут необхідні зміни. Враховуючи, що в планшетах 3.X використовуються панелі дій замість меню параметрів, як пояснюється тут:
http://developer.android.com/guide/topics/ui/menus.html#options-menu
цей хак майже напевно нічого не принесе (ні шкоди, ні користі) на планшетах 3.X.
ЗАЯВА ПРО ПРОБЛЕМУ (прочитайте це перед тим, як відповісти тригером із негативним коментарем):
Меню "Параметри" має різні стилі на різних пристроях. На деяких чисто чорний з білим текстом, на деяких чисто білий з чорним текстом. Я та багато інших розробників бажаємо контролювати колір тла комірок меню "Параметри" , а також колір тексту меню "Параметри" .
Деяким розробникам додатків потрібно лише встановити колір тла комірки (а не колір тексту), і вони можуть зробити це більш чисто, використовуючи стиль android: panelFullBackground, описаний в іншій відповіді. Однак наразі неможливо керувати кольором тексту меню "Параметри" за допомогою стилів, і тому за допомогою цього методу можна лише змінити фон на інший колір, який не змусить текст "зникнути".
Ми хотіли б зробити це за допомогою задокументованого рішення, яке може бути захищене на майбутнє, але воно просто недоступне на Android <= 2.3. Тому ми повинні використовувати рішення, яке працює в поточних версіях і розроблене, щоб мінімізувати ймовірність збою / поломки в майбутніх версіях. Ми хочемо рішення, яке елегантно повертається до поведінки за замовчуванням, якщо воно має збій.
Є багато законних причин, чому, можливо, доведеться контролювати вигляд меню "Параметри" (як правило, щоб відповідати візуальному стилю для решти додатків), тому я не буду зупинятися на цьому.
Про це викладено помилку Google Android: будь ласка, додайте свою підтримку, позначивши цю помилку зірочкою (зверніть увагу, що Google перешкоджає коментарям "мені теж": достатньо лише зірочки):
http://code.google.com/p/android/issues/detail?id=4441
КОРОТКИЙ РІШЕННЯ НАСТОЛЬКО:
Кілька плакатів пропонують зламати LayoutInflater.Factory. Пропонований хакер працював для Android <= 2.2, а не вдався для Android 2.3, оскільки хак зробив недокументоване припущення: що можна зателефонувати LayoutInflater.getView () безпосередньо, в даний час не перебуваючи всередині виклику LayoutInflater.inflate () на тому ж екземплярі LayoutInflater. Новий код в Android 2.3 порушив це припущення і призвів до NullPointerException.
Мій трохи вдосконалений хак нижче не покладається на це припущення.
Крім того, хакери також покладаються на використання внутрішнього документа без назви документа "com.android.internal.view.menu.IconMenuItemView" як рядка (а не як типу Java). Я не бачу способу уникнути цього і все ж досягти заявленої мети. Однак можна зробити хак обережно, що відступить, якщо "com.android.internal.view.menu.IconMenuItemView" не з'явиться в поточній системі.
Знову ж таки, зрозумійте, що це хакерство, і ні в якому разі я не стверджую, що це буде працювати на всіх платформах. Але ми, розробники, живемо не в фантастичному академічному світі, де все повинно бути по суті: ми маємо вирішити проблему, і ми повинні вирішити її якнайкраще. Наприклад, здається малоймовірним, що "com.android.internal.view.menu.IconMenuItemView" буде існувати на планшетах 3.X, оскільки вони використовують панелі дій замість меню параметрів.
Нарешті, деякі розробники вирішили цю проблему, повністю придушивши меню параметрів Android та написавши власний клас меню (див. Деякі посилання вище). Я не пробував цього, але якщо у вас є час написати власний подання та зрозуміти, як замінити вигляд Android (я впевнений, що диявол у деталях тут), це може бути гарним рішенням, яке не вимагає недокументовані хаки.
Злам:
Ось код.
Щоб скористатися цим кодом, викличте addOptionsMenuHackerInflaterFactory () ОДИН раз із вашої активності onCreate () або вашої діяльності onCreateOptionsMenu (). Він встановлює завод за замовчуванням, який впливатиме на подальше створення будь-якого меню параметрів. Це не впливає на вже створені меню параметрів (попередні хаки використовували ім'я функції setMenuBackground (), що дуже вводить в оману, оскільки функція не встановлює жодних властивостей меню, перш ніж вона повернеться).
@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;
}
});
}
Дякуємо за читання та насолоджуйтесь!