103 votes

Changez la couleur d'arrière plan du menu principal.

J'essaie de changer la couleur par défaut pour le menu d'options qui est blanc. Je veux un fond noir pour chaque élément du menu d'options. J'ai essayé des shootings comme Android: itemBackground = "# 000000" sur l'élément item dans l'élément de menu mais cela ne fonctionne pas. Je ne sais pas si c'est faisable ou pas. Toute idée serait la bienvenue! :)

52voto

Louis Semprini Points 581

C'est clairement un problème que beaucoup de programmeurs ont besoin et à laquelle Google n'a pas encore satisfaisante, solution de prise en charge.

Il y a beaucoup de traversé les intentions et les malentendus flottant autour de posts sur ce sujet, veuillez lire l'ensemble de cette réponse avant de répondre.

Ci-dessous je inclure un plus "raffiné" et bien commenté version du hack d'autres réponses sur cette page, en incorporant aussi des idées à partir de ces questions étroitement liées:

Change la couleur de fond du menu android

Changer la couleur de fond du menu options

Android: personnaliser l'application menu (e.g couleur d'arrière-plan)

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

Android MenuItem Bouton À Bascule

Il est possible de faire de l'Android menu options d'arrière-plan non-translucide?

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

Réglage de l'arrière-plan de menu pour être opaque

J'ai testé ce hack sur 2.1 (simulateur), 2.2 (2 dispositifs réels) et 2.3 (2 véritables appareils). Je n'ai pas de 3.X comprimés de tester encore mais afficherons les modifications nécessaires ici quand/si je ne. Étant donné que 3.X comprimés utiliser les Barres d'Action, au lieu des Options de Menus, comme expliqué ici:

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

ce hack sera presque certainement ne rien faire (pas de mal et pas bon) sur 3.X tablettes.

L'ÉNONCÉ DU PROBLÈME (à lire avant de déclencher-répondre à un commentaire négatif):

Le menu Options a énormément de styles différents sur différents appareils. Pure noir avec du texte blanc sur certaines, d'un blanc pur avec du texte noir sur certains. Moi et beaucoup d'autres développeurs souhaitent contrôler la couleur de fond du menu d'Options des cellules ainsi que la couleur du menu Options de texte.

Certains développeurs d'application n'est nécessaire que la cellule de la couleur d'arrière-plan (pas la couleur du texte), et ils peuvent le faire dans un nettoyant façon d'utiliser le android:panelFullBackground style décrit dans une autre réponse. Cependant, il n'existe actuellement aucun moyen de contrôler le menu Options de la couleur du texte avec les styles, et donc, on ne peut utiliser cette méthode pour changer le fond d'une autre couleur que de ne pas rendre le texte de "disparaître".

Nous aimerions le faire avec une documentation, solution d'avenir, mais on est tout simplement pas disponible de Android <= 2.3. Nous devons donc utiliser une solution qui fonctionne dans les versions actuelles et est conçu pour minimiser les chances de se planter/rupture dans les futures versions. Nous voulons une solution qui ne gracieusement revenir au comportement par défaut si elle a à échouer.

Il y a beaucoup de raisons légitimes pourquoi on peut avoir besoin pour contrôler l'apparence des menus Options (généralement pour correspondre à un style visuel pour le reste de l'application), donc je ne vais pas m'attarder sur ça.

Il y a un Google Android bug posté à ce sujet: s'il vous plaît ajouter votre soutien en vedette ce bug (note Google décourage "moi aussi" commentaires: juste une étoile est assez):

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

RÉSUMÉ DE SOLUTIONS JUSQU'À PRÉSENT:

Plusieurs affiches ont suggéré un hack impliquant LayoutInflater.Usine. L'suggéré hack travaillé pour Android <= 2.2 et a échoué pour Android 2.3 parce que le hack fait un sans-papiers hypothèse: que l'on pourrait appeler LayoutInflater.getView() directement, sans actuellement en cours à l'intérieur d'un appel à LayoutInflater.inflate() sur le même LayoutInflater instance. Nouveau code dans Android 2.3 a cassé cette hypothèse et a conduit à une NullPointerException.

Mes légèrement raffinée hack ci-dessous ne s'appuie pas sur cette hypothèse.

En outre, les hacks également compter sur l'aide d'un interne, sans-papiers, le nom de classe "com.android.interne.vue.menu.IconMenuItemView" comme une chaîne de caractères (pas comme un type Java). Je ne vois pas comment éviter cela et encore accomplir l'objectif déclaré. Toutefois, il est possible de faire le hack de façon prudente qui va tomber si "com.android.interne.vue.menu.IconMenuItemView" n'apparaît pas sur le système actuel.

Encore une fois, comprendre que c'est un hack et en aucun cas suis-je réclamer fonctionne sur toutes les plateformes. Mais nous les développeurs, nous ne vivons pas dans un monde fantastique monde académique, où tout doit être fait par le livre: nous avons un problème à résoudre et que nous avons à résoudre du mieux que nous le pouvons. Par exemple, il semble peu probable que la "com".android.interne.vue.menu.IconMenuItemView" existe sur 3.X tablettes, depuis qu'ils utilisent les Barres d'Action, au lieu des Options de Menus.

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

HACK:

Voici le code.

Pour utiliser ce code, appelez addOptionsMenuHackerInflaterFactory() une FOIS à partir de votre activité onCreate() ou votre activité onCreateOptionsMenu(). Il définit une valeur par défaut de l'usine, qui affecteront la création subséquente de toutes les Options de Menu. Il n'a pas d'incidence sur les Options de Menus qui ont déjà été créés (le précédent hacks utilisé un nom de fonction de setMenuBackground(), qui est très trompeur puisque la fonction n'a pas mis toutes les propriétés de menu avant de revenir).

@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 pour la lecture et profitez-en!

20voto

Pilot_51 Points 2880

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

En dépit de ce que dit la documentation, il doit être une ressource (par exemple, @android:color/black ou @drawable/my_drawable), il va se planter si vous utilisez une couleur de la valeur directement.

Cela permettra également de se débarrasser de l'élément de frontières que j'étais incapable de modifier ou de supprimer à l'aide de primalpop de la solution.

Comme pour la couleur du texte, je n'ai pas trouvé de moyen de le régler par des styles en 2.2 et je suis sûr que j'ai tout essayé (qui est la façon dont j'ai découvert l'arrière-plan du menu de l'attribut). Vous devez utiliser primalpop de solution pour cela.

13voto

Marcus Wolschon Points 777

Pour Android 2.3, ce qui peut être fait avec quelques très lourd de piratage:

La cause de problèmes avec Android 2.3 est que dans LayoutInflater le mConstructorArgs[0] = mContext est seulement au cours de l'exécution 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
    }
}

(N'hésitez pas à voter pour cette Réponse ;) ) Je l'ai testé il fonctionne sur Android 2.3 et de toujours travailler sur des versions antérieures. Si quoi que ce soit casse à nouveau plus tard dans les versions d'Android, vous allez tout simplement voir la par défaut menu de style au lieu

13voto

Viens de tomber sur cette question aussi, sur une Application qui doit être compatible avec le pain d'épice et conservent toujours autant le style de Holo-périphériques compatibles que possible.

J'ai trouvé un relativement propre solution qui a fonctionné pour moi.

Dans le thème que j'utilise un 9-patch drawable d'arrière-plan pour obtenir une couleur de fond personnalisée:

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

J'ai renoncé à tenter de style, la couleur du texte et simplement utilisé un Spannable pour définir la couleur du texte pour mon article 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;
}

9voto

dropsOfJupiter Points 1922

Une chose à noter à ce que vous les gars sont trop compliquer le problème, tout comme beaucoup d'autres messages! Tout ce que vous devez faire est de créer drawable sélecteurs avec tout ce que les fonds que vous besoin et les mettre à la réelle éléments. Je viens de passer deux heures à essayer vos solutions (l'ensemble des suggestions sur cette page) et aucun d'entre eux travaillaient. Ne pas oublier qu'il y a des tonnes d'erreurs que l'essentiel de ralentir votre performance dans ces blocs try/catch que vous avez.

De toute façon, ici, est un menu fichier 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>

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é, via le Canada, essayez google maps!

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X