Это явно проблема, с которой сталкиваются многие программисты и для которой Google еще не предоставил удовлетворительное поддерживаемое решение.
В сообщениях по этой теме есть много противоречивых намерений и недопониманий, поэтому, пожалуйста, прочтите весь ответ, прежде чем отвечать.
Ниже я привожу более «усовершенствованную» и хорошо прокомментированную версию взлома из других ответов на этой странице, также включающую идеи из этих очень тесно связанных вопросов:
Изменить цвет фона меню Android
Как изменить цвет фона меню параметров?
Android: настроить меню приложения (например, цвет фона)
http://www.macadamian.com/blog/post/android_-_theming_the_unthemable/
Кнопка переключения Android MenuItem
Можно ли сделать фон меню параметров 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 и написав свой собственный класс меню (см. Некоторые ссылки выше). Я не пробовал этого, но если у вас есть время, чтобы написать свой собственный View и выяснить, как заменить представление 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;
}
});
}
Спасибо за чтение и наслаждайтесь!