Como mudar a cor de fundo do menu de opções?

96

Estou tentando mudar a cor padrão do menu de opções, que é branco: quero um fundo preto para cada item no menu de opções.

Eu tentei algumas fotos como android: itemBackground = "# 000000" no elemento item dentro do elemento de menu, mas não funcionou.

Como posso fazer isso?

feragusper
fonte

Respostas:

65

Depois de passar um tempo considerável tentando todas as opções, a única maneira de conseguir um aplicativo usando AppCompat v7 para alterar o plano de fundo do menu flutuante foi usando o atributo itemBackground:

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

Testado da API 4.2 a 5.0.

A coisa
fonte
2
Esta deve ser a resposta aceita, fácil e simples.
Alex Ardavin
3
Mas isso remove o efeito cascata: / Como colocá-lo de volta?
David Velasquez de
Eu quero mudar o fundo da janela inteira, não separar o fundo do item, por exemplo, adicionarei bordas a cada item se você definir tal fundo (com bordas) ...
usuário25
1
E quanto à cor do texto do menu?
doctorram
51

Esse é claramente um problema que muitos programadores enfrentam e para o qual o Google ainda não forneceu uma solução compatível e satisfatória.

Existem muitas intenções cruzadas e mal-entendidos flutuando em torno das postagens sobre este tópico, portanto, leia toda esta resposta antes de responder.

Abaixo, incluo uma versão mais "refinada" e bem comentada do hack de outras respostas nesta página, também incorporando ideias dessas questões intimamente relacionadas:

Alterar a cor de fundo do menu do Android

Como mudar a cor de fundo do menu de opções?

Android: personalizar o menu do aplicativo (por exemplo, cor de fundo)

http://www.macadamian.com/blog/post/android_-_theming_the_unthemable/

Botão de alternância de item de menu do Android

É possível tornar o fundo do menu de opções do Android não translúcido?

http://www.codeproject.com/KB/android/AndroidMenusMyWay.aspx

Configurando o fundo do menu para ser opaco

Testei esse hack no 2.1 (simulador), 2.2 (2 dispositivos reais) e 2.3 (2 dispositivos reais). Não tenho nenhum tablet 3.X para testar ainda, mas postarei as alterações necessárias aqui quando / se eu tiver. Dado que os tablets 3.X usam barras de ação em vez de menus de opções, conforme explicado aqui:

http://developer.android.com/guide/topics/ui/menus.html#options-menu

este hack quase certamente não fará nada (nenhum mal e nenhum bem) em tablets 3.X.

DECLARAÇÃO DO PROBLEMA (leia isto antes de disparar e responder com um comentário negativo):

O menu Opções tem estilos muito diferentes em dispositivos diferentes. Preto puro com texto branco em alguns, branco puro com texto preto em alguns. Eu e muitos outros desenvolvedores desejamos controlar a cor de fundo das células do menu Opções , bem como a cor do texto do menu Opções .

Certos desenvolvedores de aplicativos só precisam definir a cor de fundo da célula (não a cor do texto) e podem fazer isso de maneira mais limpa usando o estilo android: panelFullBackground descrito em outra resposta. No entanto, atualmente não há como controlar a cor do texto do menu Opções com estilos e, portanto, só se pode usar esse método para alterar o plano de fundo para outra cor que não fará o texto "desaparecer".

Adoraríamos fazer isso com uma solução documentada e preparada para o futuro, mas uma simplesmente não está disponível no Android <= 2.3. Portanto, temos que usar uma solução que funcione nas versões atuais e seja projetada para minimizar as chances de travar / quebrar em versões futuras. Queremos uma solução que retorne normalmente ao comportamento padrão caso tenha que falhar.

Existem muitas razões legítimas pelas quais alguém pode precisar controlar a aparência dos menus de opções (normalmente para corresponder a um estilo visual para o resto do aplicativo), então não vou me alongar sobre isso.

Há um bug do Google Android postado sobre isso: por favor, adicione seu apoio marcando este bug (observe que o Google desencoraja comentários "eu também": apenas uma estrela é suficiente):

http://code.google.com/p/android/issues/detail?id=4441

RESUMO DAS SOLUÇÕES ATÉ AGORA:

Vários pôsteres sugeriram um hack envolvendo LayoutInflater.Factory. O hack sugerido funcionou para Android <= 2.2 e falhou para Android 2.3 porque o hack fez uma suposição não documentada: que alguém poderia chamar LayoutInflater.getView () diretamente sem estar atualmente em uma chamada para LayoutInflater.inflate () na mesma instância LayoutInflater. O novo código no Android 2.3 quebrou essa suposição e levou a uma NullPointerException.

Meu hack ligeiramente refinado abaixo não se baseia nessa suposição.

Além disso, os hacks também contam com o uso de um nome de classe interna não documentado "com.android.internal.view.menu.IconMenuItemView" como uma string (não como um tipo Java). Não vejo como evitar isso e ainda cumprir o objetivo declarado. No entanto, é possível fazer o hack de uma maneira cuidadosa, que retornará se "com.android.internal.view.menu.IconMenuItemView" não aparecer no sistema atual.

Mais uma vez, entenda que isso é um hack e de forma alguma estou afirmando que isso funcionará em todas as plataformas. Mas nós, desenvolvedores, não vivemos em um mundo acadêmico fantasioso, onde tudo tem que estar de acordo com as regras: temos um problema a resolver e temos que resolvê-lo da melhor maneira possível. Por exemplo, parece improvável que "com.android.internal.view.menu.IconMenuItemView" exista em tablets 3.X, pois eles usam barras de ação em vez de menus de opções.

Finalmente, alguns desenvolvedores resolveram esse problema suprimindo totalmente o menu de opções do Android e escrevendo sua própria classe de menu (veja alguns dos links acima). Eu não tentei isso, mas se você tiver tempo para escrever sua própria visão e descobrir como substituir a visão do Android (tenho certeza que o diabo está nos detalhes aqui), então pode ser uma boa solução que não requer nenhum hacks não documentados.

HACK:

Aqui está o código.

Para usar este código, chame addOptionsMenuHackerInflaterFactory () UMA VEZ de sua atividade onCreate () ou sua atividade onCreateOptionsMenu (). Ele define uma fábrica padrão que afetará a criação subsequente de qualquer Menu de Opções. Não afeta os menus de opções que já foram criados (os hacks anteriores usavam um nome de função setMenuBackground (), o que é muito enganoso, pois a função não define nenhuma propriedade do menu antes de retornar).

@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;
        }
    });
}

Obrigado pela leitura e divirta-se!

Louis Semprini
fonte
15
A única coisa que recebo de forma confiável ao tentar usar isso (e uma solução semelhante) é `java.lang.IllegalStateException: Uma fábrica já foi configurada neste LayoutInflater`
Bostone
Funciona para mim! Tão bom finalmente ter uma solução! Testado no Gingerbread, Honeycomb e ICS
Chad Schultz
Testado em Samsung Galaxy Nexus (4.1.1) e funcionando! Muito bom, Louis!
Felipe Caldas
2
Funciona no Galaxy Nexus 7 (4.1.1), no entanto, a cor do texto é revertida para cada chamada subsequente para o menu depois de ser oculto pela primeira vez.
Will Kru
1
Também recebo a IllegalStateException. Parece que o hack é incompatível com ActionBarSherlock, que estou usando.
Travis
20

O atributo de estilo para o plano de fundo do menu é android:panelFullBackground.

Apesar do que a documentação diz, ele precisa ser um recurso (por exemplo, @android:color/blackou @drawable/my_drawable), ele travará se você usar um valor de cor diretamente.

Isso também eliminará as bordas do item que não consegui alterar ou remover usando a solução do primalpop.

Quanto à cor do texto, não encontrei nenhuma maneira de configurá-la por meio de estilos no 2.2 e tenho certeza de que tentei de tudo (foi assim que descobri o atributo background do menu). Você precisaria usar a solução do primalpop para isso.

Pilot_51
fonte
3
Onde devo definir este valor? Não consegui fazer funcionar no Android 2.2. ou 2.3
Janusz
1
@Janusz In Styles.xml. Isso provavelmente ajudará: developer.android.com/guide/topics/resources/…
Pilot_51
2
Não funciona, ótimo se você pudesse dizer para onde deveria ir, tentei em todos os lugares, exceto para criar outro estilo para meus itens de menu atribuir ...
João
14

Para o Android 2.3, isso pode ser feito com alguns hackers muito pesados:

A causa raiz dos problemas com o Android 2.3 é que no LayoutInflater o mConstructorArgs [0] = mContext só é definido durante a execução de chamadas para

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
    }
}

Eu testei para funcionar no Android 2.3 e ainda funcionar em versões anteriores. Se algo quebrar novamente em versões posteriores do Android, você simplesmente verá o estilo de menu padrão

Marcus Wolschon
fonte
Este código funciona somente até a versão 2.1 Este código aqui parece ser melhor: stackoverflow.com/questions/2944244/…
Felipe Caldas
Olá, usei sua função, mas recebi o seguinte erro: Error inflating class com.android.internal.view.menu.IconMenuItemView e mais uma exceção Error inflating class <unknown> ... agora, o que devo fazer agora ... ? por favor me ajude.
Rushabh Patel de
13

Também tive esse problema em um aplicativo que precisava ser compatível com o Gingerbread e ainda manter o máximo possível do estilo dos dispositivos habilitados para Holo.

Eu encontrei uma solução relativamente limpa, que funcionou bem para mim.

No tema, uso um plano de fundo drawable de 9 patch para obter uma cor de plano de fundo personalizada

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

Desisti de tentar definir o estilo da cor do texto e apenas usei um Spannable para definir a cor do texto do meu item no código:

@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;
}
Nicolai Buch-Andersen
fonte
funciona muito bem para o meu problema com o uso do tema ActionBarSherlock Light em um dispositivo Gingerbread! Com isso, posso facilmente alterar o fundo do menu de opções para um cinza claro e a cor do texto para preto (os ícones já são pretos como no ActionBar! Obrigado!
florianbaethge
12

Foi assim que resolvi o meu. Acabei de especificar a cor de fundo e a cor do texto nos estilos. ou seja, res> valores> arquivo styles.xml.

<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <item name="android:itemBackground">#ffffff</item>
    <item name="android:textColor">#000000</item>
</style>
Bukunmi
fonte
1
a cor do texto mudaria em todos os lugares
user3156040
ele apenas muda a cor de fundo dos itens, e o layout das opções de menu tem preenchimento superior e inferior, não ajuda
FarshidABZ
10

Uma coisa a notar que vocês estão complicando demais o problema, assim como muitos outros posts! Tudo que você precisa fazer é criar seletores drawable com quaisquer fundos que você precisa e configurá-los para itens reais. Acabei de passar duas horas tentando suas soluções (todas sugeridas nesta página) e nenhuma delas funcionou. Sem mencionar que existem toneladas de erros que essencialmente reduzem seu desempenho nos blocos try / catch que você tem.

De qualquer forma, aqui está um arquivo xml de menu:

<?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>

Agora em seu 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>

Da próxima vez que você decidir ir ao supermercado pelo Canadá, experimente o Google Maps!

quedas de Jupiter
fonte
Eu concordo totalmente. Por que reinventar o Android quando ele =) já existe?
Fredrik
Funciona bem. Crie um drawable de lista de camadas com seu ícone e o fundo desejado. O único problema é que não sei se posso mudar a cor do texto. Portanto, nem todas as cores de fundo funcionam
Janusz
52
Bonito, elegante e totalmente não resolve o problema.
Aea
1
Se não me engano, isso apenas muda o fundo do ícone, não o item de menu em si, que permanece branco.
Jrom
3
Esta não é uma resposta à pergunta. Este é um pensamento totalmente diferente.
Kostadin
4
 <style name="AppThemeLight" parent="Theme.AppCompat.Light.NoActionBar">
    <item name="android:itemBackground">#000000</item>
</style>

Este trabalho é bom para mim

Bincy Baby
fonte
como alterar a cor do título
parvez rafi
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;
                }
            });
        }
    }
Pappachan Primal
fonte
3
Não faça isso: name.equalsIgnoreCase ("com.android.internal.view.menu.IconMenuItemView" Como o nome indica claramente, isso está usando detalhes de implementação privados e, portanto, pode quebrar em qualquer atualização de plataforma ou dispositivo.
hackbod
1
IconMenuItemView é a classe que cria e controla o menu de opções que é derivado da classe View básica. Esta classe é do código-fonte do Android e está presente desde pelo menos o api versão 5. Não consigo vê-la quebrando em nenhuma atualização de plataforma ou dispositivo.
Primal Pappachan
1
Você não pode ver porque você não pode ver o futuro. Mesmo se houvesse uma maneira de ter certeza, é uma prática ruim
HXCaine
Obrigado, isso é útil em uma pitada. No entanto, não funciona em casos especiais, como itens criados em onCreateOptionsMenu, mas desabilitados em onPrepareOptionsMenu, mas posteriormente habilitados novamente.
HRJ
3

Obrigado Marcus! Ele funciona no 2.3 sem problemas corrigindo alguns erros de sintaxe, aqui está o código corrigido

    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
fonte
1
Tudo que recebo por isso: java.lang.IllegalStateException: Uma fábrica já foi definida neste LayoutInflater
Bostone
para fazê-lo funcionar com ActionBarSherlock e estrutura de compatibilidade e evitar IllegalStateException veja este truque 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;
        }
    });
}

este é um arquivo XML

gradient 
    android:startColor="#AFAFAF" 
    android:endColor="#000000"
    android:angle="270"
shape
Android
fonte
1

Se você deseja definir uma cor arbitrária, isso parece funcionar muito bem para androidx. Testado em KitKat e Pie. Coloque isso em seu 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);
}

Isso define a cor de android.widget.PopupWindow$PopupBackgroundView, que, como você deve ter adivinhado, desenha a cor de fundo. Não há overdraw e você também pode usar cores semitransparentes.

esquilo
fonte