Как изменить цвет фона меню параметров?

96

Я пытаюсь изменить цвет по умолчанию для меню параметров, который является белым: мне нужен черный фон для каждого элемента в меню параметров.

Я пробовал снимки вроде android: itemBackground = "# 000000" в элементе item в элементе меню, но это не сработало.

Как я могу этого добиться?

Feragusper
источник

Ответы:

65

Потратив значительное количество времени на опробование всех параметров, я смог получить приложение, использующее AppCompat v7 для изменения фона меню переполнения, только с помощью атрибута itemBackground:

<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    ...
    <item name="android:itemBackground">@color/overflow_background</item>
    ...
</style>

Проверено с API 4.2 до 5.0.

Это
источник
2
Это должен быть принятый ответ, легкий и простой.
Alex Ardavin
3
Но это убирает эффект ряби: / Все равно вернуть обратно?
Дэвид Веласкес
Я хочу изменить фон всего окна, а не отдельный фон элемента, например, он добавит границы для каждого элемента, если вы установите такой фон (с границами) ...
user25
1
А как насчет цвета текста меню?
doctorram
51

Это явно проблема, с которой сталкиваются многие программисты и для которой 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;
        }
    });
}

Спасибо за чтение и наслаждайтесь!

Луи Семприни
источник
15
Единственное, что я получаю надежно, пытаясь использовать это (и подобное решение), - это `java.lang.IllegalStateException: на этом LayoutInflater уже установлена ​​фабрика`
Bostone
Работает для меня! Так здорово, что наконец-то появилось решение! Проверено на Gingerbread, Honeycomb и ICS
Chad Schultz
Проверено в Samsung Galaxy Nexus (4.1.1) и работает! Хорошая штука, Луи!
Фелипе Калдас,
2
Работает на Galaxy Nexus 7 (4.1.1), однако цвет текста восстанавливается при каждом последующем вызове меню после того, как он был скрыт в первый раз.
Will Kru
1
Я тоже получаю исключение IllegalStateException. Похоже, что взлом несовместим с ActionBarSherlock, который я использую.
Travis
20

Атрибут стиля для фона меню - android:panelFullBackground.

Несмотря на то, что говорится в документации, это должен быть ресурс (например, @android:color/blackили @drawable/my_drawable), он выйдет из строя, если вы напрямую используете значение цвета.

Это также избавит от границ элементов, которые я не смог изменить или удалить с помощью решения primalpop.

Что касается цвета текста, я не нашел способа установить его с помощью стилей в 2.2, и я уверен, что перепробовал все (именно так я обнаружил атрибут фона меню). Для этого вам нужно будет использовать решение primalpop.

Pilot_51
источник
3
Где мне установить это значение? Я не мог заставить его работать на Android 2.2. или 2.3
Януш
1
@Janusz в файле Styles.xml. Это, вероятно, поможет: developer.android.com/guide/topics/resources/…
Pilot_51,
2
Не работает, хорошо, если бы вы могли указать, куда он должен идти, пробовал везде, кроме создания другого стиля для атрибутов моих пунктов меню ...
Джон
14

Для Android 2.3 это можно сделать с помощью очень тяжелого взлома:

Основная причина проблем с Android 2.3 заключается в том, что в LayoutInflater mConstructorArgs [0] = mContext устанавливается только во время выполнения вызовов к

http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/2.3.3_r1/android/view/LayoutInflater.java/#352

protected void setMenuBackground(){

    getLayoutInflater().setFactory( new Factory() {

        @Override
        public View onCreateView (final String name, final Context context, final AttributeSet attrs ) {

            if ( name.equalsIgnoreCase( "com.android.internal.view.menu.IconMenuItemView" ) ) {

                try { // Ask our inflater to create the view
                    final LayoutInflater f = getLayoutInflater();
                    final View[] view = new View[1]:
                    try {
                        view[0] = f.createView( name, null, attrs );
                    } catch (InflateException e) {
                        hackAndroid23(name, attrs, f, view);
                    }
                    // Kind of apply our own background
                    new Handler().post( new Runnable() {
                        public void run () {
                            view.setBackgroundResource( R.drawable.gray_gradient_background);
                        }
                    } );
                    return view;
                }
                catch ( InflateException e ) {
                }
                catch ( ClassNotFoundException e ) {
                }
            }
            return null;
        }
    });
}

static void hackAndroid23(final String name,
    final android.util.AttributeSet attrs, final LayoutInflater f,
    final TextView[] view) {
    // mConstructorArgs[0] is only non-null during a running call to inflate()
    // so we make a call to inflate() and inside that call our dully XmlPullParser get's called
    // and inside that it will work to call "f.createView( name, null, attrs );"!
    try {
        f.inflate(new XmlPullParser() {
            @Override
            public int next() throws XmlPullParserException, IOException {
                try {
                    view[0] = (TextView) f.createView( name, null, attrs );
                } catch (InflateException e) {
                } catch (ClassNotFoundException e) {
                }
                throw new XmlPullParserException("exit");
            }   
        }, null, false);
    } catch (InflateException e1) {
        // "exit" ignored
    }
}

Я тестировал его на работу на Android 2.3 и на более ранние версии. Если что-то снова сломается в более поздних версиях Android, вы просто увидите стиль меню по умолчанию.

Маркус Вольшон
источник
Этот код работает только до версии 2.1. Этот код кажется лучше: stackoverflow.com/questions/2944244/…
Фелипе Калдас,
Привет, я использовал вашу функцию, но у меня возникла следующая ошибка Ошибка раздувания класса com.android.internal.view.menu.IconMenuItemView, а затем еще одно исключение Ошибка раздувания класса <unknown> ... что мне теперь делать ... ? пожалуйста, помогите мне.
Рушаб Патель,
13

Просто столкнулся с этой проблемой в приложении, которое должно было быть совместимо с Gingerbread и при этом сохранять как можно большую часть стиля от устройств с поддержкой Holo.

Я нашел относительно чистое решение, которое сработало для меня.

В теме я использую рисованный фон с 9 патчами, чтобы получить собственный цвет фона:

<style name="Theme.Styled" parent="Theme.Sherlock">
   ...
   <item name="android:panelFullBackground">@drawable/menu_hardkey_panel</item>
</style>

Я отказался от попыток стилизовать цвет текста и просто использовал Spannable, чтобы установить цвет текста для моего элемента в коде:

@Override
public boolean onCreateOptionsMenu(Menu menu) {
   MenuInflater inflater = getSupportMenuInflater();
   inflater.inflate(R.menu.actions_main, menu);

   if (android.os.Build.VERSION.SDK_INT < 
        android.os.Build.VERSION_CODES.HONEYCOMB) {

        SpannableStringBuilder text = new SpannableStringBuilder();
        text.append(getString(R.string.action_text));
        text.setSpan(new ForegroundColorSpan(Color.WHITE), 
                0, text.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

        MenuItem item1 = menu.findItem(R.id.action_item1);
        item1.setTitle(text);
   }

   return true;
}
Николай Бух-Андерсен
источник
отлично подходит для моей проблемы с использованием темы ActionBarSherlock Light на устройстве Gingerbread! Благодаря этому я могу легко изменить фон меню параметров на светло-серый, а цвет текста на черный (значки уже черные, как в
панели действий
13

Вот как я решил свою. Я просто указал цвет фона и цвет текста в стилях. т.е. res> values> файл styles.xml.

<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <item name="android:itemBackground">#ffffff</item>
    <item name="android:textColor">#000000</item>
</style>
Букунми
источник
1
цвет текста будет меняться везде
user3156040 03
он просто меняет цвет фона элементов, а макет опций меню имеет верхнее и нижнее отступы, это не помогает
FarshidABZ
10

Следует отметить, что вы, ребята, слишком усложняете проблему, как и многие другие сообщения! Все, что вам нужно сделать, это создать настраиваемые селекторы с любым нужным вам фоном и установить их на реальные элементы. Я просто провожу два часа, пробуя ваши решения (все предложенные на этой странице), и ни одно из них не сработало. Не говоря уже о том, что существует множество ошибок, которые существенно замедляют вашу производительность в тех блоках try / catch, которые у вас есть.

В любом случае вот XML-файл меню:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/m1"
          android:icon="@drawable/item1_selector"
          />
    <item android:id="@+id/m2"
          android:icon="@drawable/item2_selector"
          />
</menu>

Теперь в вашем item1_selector:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="true" android:drawable="@drawable/item_highlighted" />
    <item android:state_selected="true" android:drawable="@drawable/item_highlighted" />
    <item android:state_focused="true" android:drawable="@drawable/item_nonhighlighted" />
    <item android:drawable="@drawable/item_nonhighlighted" />
</selector>

В следующий раз, когда вы решите пойти в супермаркет через Канаду, попробуйте карты Google!

капли Юпитера
источник
Я абсолютно согласен. Зачем изобретать Android, если он =) уже существует?
Фредрик
Прекрасно работает. Создайте список слоев с вашим значком и желаемым фоном. Единственная проблема в том, что я не знаю, могу ли я изменить цвет текста. Поэтому не каждый цвет фона работает
Януш
52
Красиво, элегантно и совершенно не решает проблему.
Aea
1
Если я не ошибаюсь, это просто меняет фон значка, а не сам пункт меню, который остается белым.
Jrom
3
Это не ответ на вопрос. Это совершенно другое мнение.
Костадин
4
 <style name="AppThemeLight" parent="Theme.AppCompat.Light.NoActionBar">
    <item name="android:itemBackground">#000000</item>
</style>

это отлично работает для меня

Бинси Бэби
источник
как изменить цвет заголовка
парвез рафи
3
    /* 
     *The Options Menu (the one that pops up on pressing the menu button on the emulator) 
     * can be customized to change the background of the menu 
     *@primalpop  
   */ 

    package com.pop.menu;

    import android.app.Activity;
    import android.content.Context;
    import android.os.Bundle;
    import android.os.Handler;
    import android.util.AttributeSet;
    import android.util.Log;
    import android.view.InflateException;
    import android.view.LayoutInflater;
    import android.view.Menu;
    import android.view.MenuInflater;
    import android.view.View;
    import android.view.LayoutInflater.Factory;

    public class Options_Menu extends Activity {

        private static final String TAG = "DEBUG";

        /** Called when the activity is first created. */
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);

        }

        /* Invoked when the menu button is pressed */

        @Override
        public boolean onCreateOptionsMenu(Menu menu) {
            // TODO Auto-generated method stub
            super.onCreateOptionsMenu(menu);
            MenuInflater inflater = new MenuInflater(getApplicationContext());
            inflater.inflate(R.menu.options_menu, menu);
            setMenuBackground();
            return true;
        }

        /*IconMenuItemView is the class that creates and controls the options menu 
         * which is derived from basic View class. So We can use a LayoutInflater 
         * object to create a view and apply the background.
         */
        protected void setMenuBackground(){

            Log.d(TAG, "Enterting setMenuBackGround");
            getLayoutInflater().setFactory( new Factory() {

                @Override
                public View onCreateView ( String name, Context context, AttributeSet attrs ) {

                    if ( name.equalsIgnoreCase( "com.android.internal.view.menu.IconMenuItemView" ) ) {

                        try { // Ask our inflater to create the view
                            LayoutInflater f = getLayoutInflater();
                            final View view = f.createView( name, null, attrs );
                            /* 
                             * The background gets refreshed each time a new item is added the options menu. 
                             * So each time Android applies the default background we need to set our own 
                             * background. This is done using a thread giving the background change as runnable
                             * object
                             */
                            new Handler().post( new Runnable() {
                                public void run () {
                                    view.setBackgroundResource( R.drawable.background);
                                }
                            } );
                            return view;
                        }
                        catch ( InflateException e ) {}
                        catch ( ClassNotFoundException e ) {}
                    }
                    return null;
                }
            });
        }
    }
Первобытный Паппачан
источник
3
Пожалуйста, не делайте этого: name.equalsIgnoreCase ("com.android.internal.view.menu.IconMenuItemView" Как ясно видно из названия, это использует частные детали реализации и, таким образом, может сломаться на любом обновлении платформы или устройстве.
hackbod
1
IconMenuItemView - это класс, который создает и управляет меню параметров, производным от базового класса View. Этот класс взят из исходного кода Android и присутствует, по крайней мере, с версии 5 api. Я не вижу, чтобы он ломался ни на одном обновлении платформы или устройстве.
Primal Pappachan
1
Вы не можете этого видеть, потому что не можете видеть будущее. Даже если бы был способ быть уверенным, это плохая практика
HXCaine
Спасибо, это пригодится в крайнем случае. Однако не работает в особых случаях, таких как элементы, созданные в onCreateOptionsMenu, но отключенные в onPrepareOptionsMenu, но затем снова включенные.
HRJ 08
3

Спасибо, Маркус! Он работает на 2.3 плавно, исправляя некоторые синтаксические ошибки, вот исправленный код

    protected void setMenuBackground() {
    getLayoutInflater().setFactory(new Factory() {

        @Override
        public View onCreateView(final String name, final Context context,
                final AttributeSet attrs) {

            if (name.equalsIgnoreCase("com.android.internal.view.menu.IconMenuItemView")) {

                try { // Ask our inflater to create the view
                    final LayoutInflater f = getLayoutInflater();
                    final View[] view = new View[1];
                    try {
                        view[0] = f.createView(name, null, attrs);
                    } catch (InflateException e) {
                        hackAndroid23(name, attrs, f, view);
                    }
                    // Kind of apply our own background
                    new Handler().post(new Runnable() {
                        public void run() {
                            view[0].setBackgroundColor(Color.WHITE);

                        }
                    });
                    return view[0];
                } catch (InflateException e) {
                } catch (ClassNotFoundException e) {

                }
            }
            return null;
        }
    });
}

static void hackAndroid23(final String name,
        final android.util.AttributeSet attrs, final LayoutInflater f,
        final View[] view) {
    // mConstructorArgs[0] is only non-null during a running call to
    // inflate()
    // so we make a call to inflate() and inside that call our dully
    // XmlPullParser get's called
    // and inside that it will work to call
    // "f.createView( name, null, attrs );"!
    try {
        f.inflate(new XmlPullParser() {
            @Override
            public int next() throws XmlPullParserException, IOException {
                try {
                    view[0] = (TextView) f.createView(name, null, attrs);
                } catch (InflateException e) {
                } catch (ClassNotFoundException e) {
                }
                throw new XmlPullParserException("exit");
            }
        }, null, false);
    } catch (InflateException e1) {
        // "exit" ignored
    }
}
Halo Ha
источник
1
Все, что я получаю за это: java.lang.IllegalStateException: на этом LayoutInflater уже установлена ​​фабрика
Бостон
чтобы заставить его работать с ActionBarSherlock и фреймворком совместимости и избежать IllegalStateException, см. этот трюк stackoverflow.com/questions/13415284/…
avianey
3
protected void setMenuBackground() {
    getLayoutInflater().setFactory(new Factory() {
        @Override
        public View onCreateView (String name, Context context, AttributeSet attrs) {
            if (name.equalsIgnoreCase("com.android.internal.view.menu.IconMenuItemView")) {
                try {
                    // Ask our inflater to create the view
                    LayoutInflater f = getLayoutInflater();
                    final View view = f.createView(name, null, attrs);
                    // Kind of apply our own background
                    new Handler().post( new Runnable() {
                        public void run () {
                            view.setBackgroundResource(R.drawable.gray_gradient_background);
                        }
                    });
                    return view;
                }
                catch (InflateException e) {
                }
                catch (ClassNotFoundException e) {
                }
            }
            return null;
        }
    });
}

это файл XML

gradient 
    android:startColor="#AFAFAF" 
    android:endColor="#000000"
    android:angle="270"
shape
Android
источник
1

Если вы хотите установить произвольный цвет, это сработает довольно хорошо androidx. Проверено на KitKat и Pie. Поместите это в свой AppCompatActivity:

@Override public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
    if (name.equals("androidx.appcompat.view.menu.ListMenuItemView") &&
            parent.getParent() instanceof FrameLayout) {
            ((View) parent.getParent()).setBackgroundColor(yourFancyColor);
    }
    return super.onCreateView(parent, name, context, attrs);
}

Это устанавливает цвет android.widget.PopupWindow$PopupBackgroundView, который, как вы могли догадаться, отрисовывает цвет фона. Здесь нет перерисовки, вы также можете использовать полупрозрачные цвета.

белка
источник