Comment changer la couleur de fond du menu d'options?

96

J'essaie de changer la couleur par défaut du menu d'options qui est blanc: je veux un fond noir pour chaque élément du menu d'options.

J'ai essayé quelques prises de vue comme android: itemBackground = "# 000000" sur l'élément item dans l'élément menu mais cela n'a pas fonctionné.

Comment puis-je accomplir cela?

feragusper
la source

Réponses:

65

Après avoir passé un temps considérable à essayer toutes les options, la seule façon d'obtenir une application utilisant AppCompat v7 pour modifier l'arrière-plan du menu de débordement était d'utiliser l'attribut itemBackground:

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

Testé de l'API 4.2 à 5.0.

TheIT
la source
2
Cela devrait être la réponse acceptée, facile et simple.
Alex Ardavin
3
Mais cela supprime l'effet d'entraînement: / Quoi qu'il en soit pour le remettre?
David Velasquez
Je veux changer tout l'arrière-plan de la fenêtre, pas l'arrière-plan de l'élément séparé, par exemple, il ajoutera des bordures à chaque élément si vous définissez un tel arrière-plan (avec des bordures) ...
user25
1
Qu'en est-il de la couleur du texte du menu?
doctorram le
51

C'est clairement un problème rencontré par de nombreux programmeurs et auquel Google n'a pas encore fourni de solution satisfaisante et prise en charge.

Il y a beaucoup d'intentions croisées et de malentendus flottant autour des articles sur ce sujet, alors veuillez lire toute cette réponse avant de répondre.

Ci-dessous, j'inclus une version plus "raffinée" et bien commentée du hack d'autres réponses sur cette page, incorporant également des idées de ces questions très étroitement liées:

Changer la couleur d'arrière-plan du menu Android

Comment changer la couleur de fond du menu d'options?

Android: personnaliser le menu de l'application (par exemple, la couleur de fond)

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

Bouton Android Menu

Est-il possible de rendre l'arrière-plan du menu des options Android non translucide?

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

Définition de l'arrière-plan du menu pour être opaque

J'ai testé ce hack sur 2.1 (simulateur), 2.2 (2 vrais appareils) et 2.3 (2 vrais appareils). Je n'ai pas encore de tablette 3.X à tester, mais je publierai les modifications nécessaires ici si / si je le fais. Étant donné que les tablettes 3.X utilisent des barres d'action au lieu des menus d'options, comme expliqué ici:

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

ce hack ne fera presque certainement rien (ni mal ni bon) sur les tablettes 3.X.

ÉNONCÉ DU PROBLÈME (lisez ceci avant de répondre au déclencheur avec un commentaire négatif):

Le menu Options a des styles très différents sur différents appareils. Noir pur avec du texte blanc sur certains, blanc pur avec du texte noir sur certains. Moi-même et de nombreux autres développeurs souhaitons contrôler la couleur d'arrière-plan des cellules du menu Options ainsi que la couleur du texte du menu Options .

Certains développeurs d'applications n'ont besoin que de définir la couleur d'arrière-plan de la cellule (pas la couleur du texte), et ils peuvent le faire de manière plus propre en utilisant le style android: panelFullBackground décrit dans une autre réponse. Cependant, il n'existe actuellement aucun moyen de contrôler la couleur du texte du menu Options avec des styles, et on ne peut donc utiliser cette méthode que pour changer l'arrière-plan en une autre couleur qui ne fera pas «disparaître» le texte.

Nous serions ravis de le faire avec une solution documentée et pérenne, mais l'une d'entre elles n'est tout simplement pas disponible à partir d'Android <= 2.3. Nous devons donc utiliser une solution qui fonctionne dans les versions actuelles et qui est conçue pour minimiser les risques de plantage / rupture dans les versions futures. Nous voulons une solution qui échoue correctement au comportement par défaut si elle doit échouer.

Il existe de nombreuses raisons légitimes pour lesquelles il peut être nécessaire de contrôler l'apparence des menus d'options (généralement pour correspondre à un style visuel pour le reste de l'application), je ne m'attarderai donc pas là-dessus.

Il y a un bug Google Android à ce sujet: veuillez ajouter votre soutien en mettant en vedette ce bug (notez que Google décourage les commentaires "moi aussi": juste une étoile suffit):

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

RÉSUMÉ DES SOLUTIONS À CE JOUR:

Plusieurs affiches ont suggéré un hack impliquant LayoutInflater.Factory. Le piratage suggéré a fonctionné pour Android <= 2.2 et a échoué pour Android 2.3 parce que le piratage a fait une hypothèse non documentée: qu'on pourrait appeler LayoutInflater.getView () directement sans être actuellement dans un appel à LayoutInflater.inflate () sur la même instance de LayoutInflater. Le nouveau code dans Android 2.3 a cassé cette hypothèse et a conduit à une NullPointerException.

Mon hack légèrement raffiné ci-dessous ne repose pas sur cette hypothèse.

En outre, les hacks reposent également sur l'utilisation d'un nom de classe interne non documenté "com.android.internal.view.menu.IconMenuItemView" en tant que chaîne (pas en tant que type Java). Je ne vois aucun moyen d'éviter cela et d'atteindre toujours l'objectif déclaré. Cependant, il est possible de faire le piratage d'une manière prudente qui se rabattra si "com.android.internal.view.menu.IconMenuItemView" n'apparaît pas sur le système actuel.

Encore une fois, comprenez qu'il s'agit d'un hack et je ne prétends en aucun cas que cela fonctionnera sur toutes les plates-formes. Mais nous, les développeurs, ne vivons pas dans un monde académique fantastique où tout doit être écrit: nous avons un problème à résoudre et nous devons le résoudre du mieux que nous pouvons. Par exemple, il semble peu probable que "com.android.internal.view.menu.IconMenuItemView" existe sur les tablettes 3.X car elles utilisent des barres d'action au lieu des menus d'options.

Enfin, certains développeurs ont résolu ce problème en supprimant totalement le menu d'options Android et en écrivant leur propre classe de menu (voir certains des liens ci-dessus). Je n'ai pas essayé cela, mais si vous avez le temps d'écrire votre propre vue et de trouver comment remplacer la vue d'Android (je suis sûr que le diable est dans les détails ici), alors cela pourrait être une bonne solution qui ne nécessite aucun hacks non documentés.

PIRATER:

Voici le code.

Pour utiliser ce code, appelez addOptionsMenuHackerInflaterFactory () UNE FOIS depuis votre activité onCreate () ou votre activité onCreateOptionsMenu (). Il définit une usine par défaut qui affectera la création ultérieure de tout menu d'options. Cela n'affecte pas les menus d'options qui ont déjà été créés (les hacks précédents utilisaient un nom de fonction de setMenuBackground (), ce qui est très trompeur car la fonction ne définit aucune propriété de menu avant son retour).

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

Merci d'avoir lu et amusez-vous!

Louis Semprini
la source
15
La seule chose que j'obtiens de manière fiable en essayant d'utiliser cette solution (et une solution similaire) est `java.lang.IllegalStateException: Une usine a déjà été définie sur ce LayoutInflater`
Bostone
Travaille pour moi! Tellement génial d'avoir enfin une solution! Testé sur Gingerbread, Honeycomb et ICS
Chad Schultz
Testé sur Samsung Galaxy Nexus (4.1.1) et fonctionne! Du bon matos, Louis!
Felipe Caldas le
2
Fonctionne sur Galaxy Nexus 7 (4.1.1), mais la couleur du texte est inversée pour chaque appel ultérieur au menu après avoir été masquée pour la première fois.
Will Kru
1
J'obtiens également l'exception IllegalStateException. Il semble que le hack soit incompatible avec ActionBarSherlock, que j'utilise.
Travis
20

L'attribut de style pour l'arrière-plan du menu est android:panelFullBackground.

Malgré ce que dit la documentation, il doit s'agir d'une ressource (par exemple @android:color/blackou @drawable/my_drawable), il plantera si vous utilisez directement une valeur de couleur.

Cela supprimera également les bordures des éléments que je n'ai pas pu modifier ou supprimer à l'aide de la solution de primalpop.

En ce qui concerne la couleur du texte, je n'ai trouvé aucun moyen de la définir via les styles de la version 2.2 et je suis sûr que j'ai tout essayé (c'est ainsi que j'ai découvert l'attribut d'arrière-plan du menu). Vous auriez besoin d'utiliser la solution de primalpop pour cela.

Pilot_51
la source
3
Où dois-je définir cette valeur? Je n'ai pas pu le faire fonctionner sur Android 2.2. ou 2.3
Janusz
1
@Janusz dans Styles.xml. Cela aidera probablement: developer.android.com/guide/topics/resources/…
Pilot_51
2
Ne fonctionne pas, bien si vous pouviez indiquer où il est censé aller, essayé partout sauf pour créer un autre style pour mes éléments de menu à attribuer .....
John
14

Pour Android 2.3, cela peut être fait avec un piratage très lourd:

La cause première des problèmes avec Android 2.3 est que dans LayoutInflater, mConstructorArgs [0] = mContext n'est défini que lors des appels à

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

Je l'ai testé pour fonctionner sur Android 2.3 et pour continuer à fonctionner sur des versions antérieures. Si quelque chose se brise à nouveau dans les versions ultérieures d'Android, vous verrez simplement le style de menu par défaut à la place

Marcus Wolschon
la source
Ce code ne fonctionne que jusqu'à la version 2.1 Ce code semble ici être meilleur: stackoverflow.com/questions/2944244/…
Felipe Caldas
Salut, j'ai utilisé votre fonction mais j'ai eu cette erreur suivante Erreur de gonflage de la classe com.android.internal.view.menu.IconMenuItemView , puis une autre exception Erreur de gonflage de la classe <inconnu> ... maintenant que dois-je faire maintenant ... ? Aidez-moi, s'il vous plaît.
Rushabh Patel
13

Je viens de rencontrer ce problème aussi, sur une application qui devait être compatible avec Gingerbread tout en conservant autant que possible le style des appareils compatibles Holo.

J'ai trouvé une solution relativement propre, qui a bien fonctionné pour moi.

Dans le thème, j'utilise un arrière-plan dessinable à 9 patchs pour obtenir une couleur d'arrière-plan personnalisée:

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

J'ai renoncé à essayer de styliser la couleur du texte et j'ai simplement utilisé un Spannable pour définir la couleur du texte de mon élément dans le code:

@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
la source
fonctionne très bien pour mon problème avec l'utilisation du thème ActionBarSherlock Light sur un appareil Gingerbread! Avec cela, je peux facilement changer l'arrière-plan du menu d'options en gris clair et la couleur du texte en noir (les icônes sont déjà noires comme dans l'ActionBar! Merci!
florianbaethge
12

C'est ainsi que j'ai résolu le mien. Je viens de spécifier la couleur d'arrière-plan et la couleur du texte dans les styles. ie res> values> fichier styles.xml.

<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <item name="android:itemBackground">#ffffff</item>
    <item name="android:textColor">#000000</item>
</style>
Bukunmi
la source
1
textcolor changerait partout
user3156040
cela change simplement la couleur d'arrière-plan des éléments, et la disposition des options de menu a un rembourrage en haut et en bas, cela n'aide pas
FarshidABZ
10

Une chose à noter que vous compliquez trop le problème, tout comme beaucoup d'autres articles! Tout ce que vous avez à faire est de créer des sélecteurs dessinables avec les arrière-plans dont vous avez besoin et de les définir sur des éléments réels. Je viens de passer deux heures à essayer vos solutions (toutes suggérées sur cette page) et aucune d'elles n'a fonctionné. Sans oublier qu'il existe des tonnes d'erreurs qui ralentissent essentiellement vos performances dans les blocs try / catch que vous avez.

Quoi qu'il en soit, voici un fichier 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>

Maintenant dans votre 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>

La prochaine fois que vous décidez d'aller au supermarché à travers le Canada, essayez google maps!

les rejets de Jupiter
la source
Je suis tout à fait d'accord. Pourquoi réinventer Android alors qu'il =) existe déjà?
Fredrik
Fonctionne très bien. Construisez une liste de calques dessinable avec votre icône et l'arrière-plan souhaité. Le seul problème est que je ne sais pas si je peux changer la couleur du texte. Par conséquent, toutes les couleurs de fond ne fonctionnent pas
Janusz
52
Beau, élégant et ne résout absolument pas le problème.
Aea
1
Si je ne me trompe pas, cela change simplement l'arrière-plan de l'icône, pas l'élément de menu lui-même, qui reste blanc.
Jrom
3
Ce n'est pas une réponse à une question. C'est une pensée totalement différente.
Kostadin
4
 <style name="AppThemeLight" parent="Theme.AppCompat.Light.NoActionBar">
    <item name="android:itemBackground">#000000</item>
</style>

cela fonctionne bien pour moi

Bincy bébé
la source
comment changer la couleur du titre
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;
                }
            });
        }
    }
Primal Pappachan
la source
3
Veuillez ne pas faire ceci: name.equalsIgnoreCase ("com.android.internal.view.menu.IconMenuItemView" Comme son nom l'indique clairement, cela utilise des détails d'implémentation privés, et peut donc être interrompu sur n'importe quelle mise à jour de plate-forme ou appareil.
hackbod
1
IconMenuItemView est la classe qui crée et contrôle le menu d'options qui est dérivé de la classe View de base. Cette classe provient du code source d'Android et est présente depuis au moins la version 5 de l'API. Je ne peux pas la voir se briser sur une mise à jour de plate-forme ou un appareil.
Primal Pappachan
1
Vous ne pouvez pas le voir parce que vous ne pouvez pas voir l'avenir. Même s'il y avait un moyen d'en être sûr, c'est une mauvaise pratique
HXCaine
Merci, c'est utile à la rigueur. Cependant, ne fonctionne pas dans des cas particuliers, tels que les éléments créés dans onCreateOptionsMenu, mais désactivés dans onPrepareOptionsMenu, puis réactivés ultérieurement.
HRJ
3

Merci Marcus! Il fonctionne sur 2.3 en douceur en corrigeant certaines erreurs de syntaxe, voici le code corrigé

    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
la source
1
Tout ce que j'obtiens pour ceci: java.lang.IllegalStateException: Une usine a déjà été définie sur ce LayoutInflater
Bostone
pour le faire fonctionner avec ActionBarSherlock et le framework de compatibilité et éviter IllegalStateException voir cette astuce 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;
        }
    });
}

c'est un fichier XML

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

Si vous souhaitez définir une couleur arbitraire, cela semble plutôt bien fonctionner androidx. Testé sur KitKat et Pie. Mettez ceci dans votre 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);
}

Cela définit la couleur de android.widget.PopupWindow$PopupBackgroundView, qui, comme vous l'avez peut-être deviné, dessine la couleur d'arrière-plan. Il n'y a pas de dégagement et vous pouvez également utiliser des couleurs semi-transparentes.

écureuil
la source