Wie ändere ich die Hintergrundfarbe des Optionsmenüs?

96

Ich versuche, die Standardfarbe für das Optionsmenü zu ändern, das weiß ist: Ich möchte einen schwarzen Hintergrund für jedes Element im Optionsmenü.

Ich habe einige Aufnahmen wie android: itemBackground = "# 000000" für das item-Element im Menüelement versucht, aber es hat nicht funktioniert.

Wie kann ich das erreichen?

Feragusper
quelle

Antworten:

65

Nachdem ich viel Zeit damit verbracht hatte, alle Optionen auszuprobieren, konnte ich mit AppCompat v7 eine App zum Ändern des Hintergrunds des Überlaufmenüs erhalten, indem ich das Attribut itemBackground verwendete:

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

Getestet von API 4.2 bis 5.0.

Das es
quelle
2
Dies sollte die akzeptierte Antwort sein, leicht und einfach.
Alex Ardavin
3
Aber das beseitigt den Welleneffekt: / Wie auch immer, um es zurückzusetzen?
David Velasquez
Ich möchte den Hintergrund des gesamten Fensters ändern, nicht den Hintergrund eines separaten Elements. Beispielsweise werden jedem Element Rahmen hinzugefügt, wenn Sie einen solchen Hintergrund (mit Rahmen)
festlegen
1
Was ist mit der Menütextfarbe?
Doctorram
51

Dies ist eindeutig ein Problem, das viele Programmierer haben und für das Google noch keine zufriedenstellende, unterstützte Lösung bereitstellen muss.

Es gibt viele gekreuzte Absichten und Missverständnisse in den Beiträgen zu diesem Thema. Lesen Sie daher bitte die gesamte Antwort, bevor Sie antworten.

Im Folgenden füge ich eine "verfeinerte" und gut kommentierte Version des Hacks aus anderen Antworten auf dieser Seite hinzu, die auch Ideen aus diesen sehr eng verwandten Fragen enthält:

Ändern Sie die Hintergrundfarbe des Android-Menüs

Wie ändere ich die Hintergrundfarbe des Optionsmenüs?

Android: Menü der Anwendung anpassen (z. B. Hintergrundfarbe)

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

Android MenuItem Umschalttaste

Ist es möglich, den Hintergrund des Android-Optionsmenüs nicht durchscheinend zu machen?

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

Einstellen des Menühintergrunds auf undurchsichtig

Ich habe diesen Hack auf 2.1 (Simulator), 2.2 (2 echte Geräte) und 2.3 (2 echte Geräte) getestet. Ich habe noch keine 3.X-Tablets zum Testen, werde aber alle erforderlichen Änderungen hier veröffentlichen, wenn / falls ich dies tue. Angesichts der Tatsache, dass 3.X-Tablets Aktionsleisten anstelle von Optionsmenüs verwenden, wie hier erläutert:

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

Dieser Hack wird mit ziemlicher Sicherheit nichts (kein Schaden und kein Nutzen) auf 3.X-Tablets bewirken.

STELLUNGNAHME DES PROBLEMS (lesen Sie dies, bevor Sie mit einem negativen Kommentar auf den Auslöser antworten):

Das Optionsmenü hat auf verschiedenen Geräten sehr unterschiedliche Stile. Reines Schwarz mit weißem Text auf einigen, reines Weiß mit schwarzem Text auf einigen. Ich und viele andere Entwickler möchten die Hintergrundfarbe der Optionsmenüzellen sowie die Farbe des Optionsmenütextes steuern .

Bestimmte App-Entwickler müssen nur die Hintergrundfarbe der Zelle festlegen (nicht die Textfarbe), und dies können sie mit dem in einer anderen Antwort beschriebenen android: panelFullBackground-Stil sauberer tun. Derzeit gibt es jedoch keine Möglichkeit, die Textfarbe des Optionsmenüs mit Stilen zu steuern. Daher kann diese Methode nur verwendet werden, um den Hintergrund in eine andere Farbe zu ändern, die den Text nicht "verschwinden" lässt.

Wir würden dies gerne mit einer dokumentierten, zukunftssicheren Lösung tun, aber eine ist ab Android <= 2.3 einfach nicht verfügbar. Daher müssen wir eine Lösung verwenden, die in aktuellen Versionen funktioniert und die Wahrscheinlichkeit eines Absturzes / Bruches in zukünftigen Versionen minimiert. Wir wollen eine Lösung, die ordnungsgemäß zum Standardverhalten zurückfällt, wenn sie fehlschlagen muss.

Es gibt viele legitime Gründe, warum man möglicherweise das Aussehen von Optionsmenüs steuern muss (normalerweise, um einem visuellen Stil für den Rest der App zu entsprechen), damit ich nicht weiter darauf eingehen werde.

Es gibt einen Google Android-Fehler, der dazu gepostet wurde: Bitte fügen Sie Ihre Unterstützung hinzu, indem Sie diesen Fehler markieren (Hinweis: Google rät von "Ich auch" -Kommentaren ab: Nur ein Stern ist genug):

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

ZUSAMMENFASSUNG DER LÖSUNGEN Bisher:

Mehrere Poster haben einen Hack mit LayoutInflater.Factory vorgeschlagen. Der vorgeschlagene Hack funktionierte für Android <= 2.2 und schlug für Android 2.3 fehl, da der Hack eine undokumentierte Annahme machte: Man könnte LayoutInflater.getView () direkt aufrufen, ohne sich derzeit in einem Aufruf von LayoutInflater.inflate () auf derselben LayoutInflater-Instanz zu befinden. Neuer Code in Android 2.3 hat diese Annahme gebrochen und zu einer NullPointerException geführt.

Mein leicht verfeinerter Hack unten beruht nicht auf dieser Annahme.

Darüber hinaus basieren die Hacks auch auf der Verwendung eines internen, nicht dokumentierten Klassennamens "com.android.internal.view.menu.IconMenuItemView" als Zeichenfolge (nicht als Java-Typ). Ich sehe keinen Weg, dies zu vermeiden und trotzdem das erklärte Ziel zu erreichen. Es ist jedoch möglich, den Hack auf eine vorsichtige Weise durchzuführen, die zurückfällt, wenn "com.android.internal.view.menu.IconMenuItemView" auf dem aktuellen System nicht angezeigt wird.

Verstehe wieder, dass dies ein Hack ist und ich behaupte keineswegs, dass dies auf allen Plattformen funktionieren wird. Aber wir Entwickler leben nicht in einer akademischen Fantasy-Welt, in der alles nach dem Buch sein muss: Wir haben ein Problem zu lösen und wir müssen es so gut wie möglich lösen. Beispielsweise ist es unwahrscheinlich, dass "com.android.internal.view.menu.IconMenuItemView" auf 3.X-Tablets vorhanden ist, da sie Aktionsleisten anstelle von Optionsmenüs verwenden.

Schließlich haben einige Entwickler dieses Problem gelöst, indem sie das Android-Optionsmenü vollständig unterdrückt und ihre eigene Menüklasse geschrieben haben (siehe einige der obigen Links). Ich habe das noch nicht ausprobiert, aber wenn Sie Zeit haben, Ihre eigene Ansicht zu schreiben und herauszufinden, wie Sie die Ansicht von Android ersetzen können (ich bin sicher, der Teufel steckt hier im Detail), ist dies möglicherweise eine nette Lösung, für die keine erforderlich ist undokumentierte Hacks.

HACKEN:

Hier ist der Code.

Um diesen Code zu verwenden, rufen Sie addOptionsMenuHackerInflaterFactory () EINMAL von Ihrer Aktivität onCreate () oder Ihrer Aktivität onCreateOptionsMenu () auf. Es wird eine Standardfactory festgelegt, die sich auf die spätere Erstellung eines Optionsmenüs auswirkt. Es hat keine Auswirkungen auf bereits erstellte Optionsmenüs (die vorherigen Hacks verwendeten den Funktionsnamen setMenuBackground (), was sehr irreführend ist, da die Funktion vor ihrer Rückkehr keine Menüeigenschaften festlegt).

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

Danke fürs Lesen und viel Spaß!

Louis Semprini
quelle
15
Das einzige, was ich zuverlässig bekomme, wenn ich versuche, diese (und ähnliche) Lösung zu verwenden, ist `java.lang.IllegalStateException: Auf diesem LayoutInflater wurde bereits eine Factory eingerichtet
Bostone
Funktioniert bei mir! So toll, endlich eine Lösung zu haben! Getestet auf Lebkuchen, Waben und ICS
Chad Schultz
Getestet in Samsung Galaxy Nexus (4.1.1) und funktioniert! Gutes Zeug, Louis!
Felipe Caldas
2
Funktioniert auf dem Galaxy Nexus 7 (4.1.1), die Textfarbe wird jedoch bei jedem nachfolgenden Aufruf des Menüs nach dem ersten Ausblenden zurückgesetzt.
Will Kru
1
Ich bekomme auch die IllegalStateException. Es sieht so aus, als ob der Hack nicht mit ActionBarSherlock kompatibel ist, das ich verwende.
Travis
20

Das Stilattribut für den Menühintergrund lautet android:panelFullBackground.

Trotz der Angaben in der Dokumentation muss es sich um eine Ressource handeln (z. B. @android:color/blackoder @drawable/my_drawable). Sie stürzt ab, wenn Sie einen Farbwert direkt verwenden.

Dadurch werden auch die Artikelränder entfernt, die ich mit der Lösung von primalpop nicht ändern oder entfernen konnte.

Was die Textfarbe betrifft, habe ich in 2.2 keine Möglichkeit gefunden, sie durch Stile festzulegen, und ich bin sicher, dass ich alles ausprobiert habe (so habe ich das Menü-Hintergrundattribut entdeckt). Dafür müssten Sie die Lösung von primalpop verwenden.

Pilot_51
quelle
3
Wo muss ich diesen Wert einstellen? Ich konnte es unter Android 2.2 nicht zum Laufen bringen. oder 2.3
Janusz
1
@ Janusz In Styles.xml. Dies wird wahrscheinlich helfen: developer.android.com/guide/topics/resources/…
Pilot_51
2
Funktioniert nicht, schön, wenn Sie angeben könnten, wohin es gehen soll, überall versucht, außer einen anderen Stil für meine Menüelemente zu erstellen .....
John
14

Für Android 2.3 kann dies mit sehr starkem Hacking geschehen:

Die Hauptursache für die Probleme mit Android 2.3 ist, dass in LayoutInflater der mConstructorArgs [0] = mContext nur während der Ausführung von Aufrufen von festgelegt wird

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

Ich habe es getestet, um mit Android 2.3 zu arbeiten und um noch mit früheren Versionen zu arbeiten. Wenn in späteren Android-Versionen erneut Probleme auftreten, wird stattdessen einfach der Standardmenüstil angezeigt

Marcus Wolschon
quelle
Dieser Code läuft nur bis Version 2.1 Dieser Code hier scheint besser zu sein: stackoverflow.com/questions/2944244/…
Felipe Caldas
Hallo, ich habe Ihre Funktion verwendet, aber ich habe den folgenden Fehler erhalten: Fehler beim Aufblasen der Klasse com.android.internal.view.menu.IconMenuItemView und dann noch eine Ausnahme Fehler beim Aufblasen der Klasse <unbekannt> ... was soll ich jetzt tun ? ? Bitte hilf mir.
Rushabh Patel
13

Ich bin auch auf dieses Problem gestoßen, und zwar auf einer App, die mit Gingerbread kompatibel sein musste und dennoch so viel Styling wie möglich von Holo-fähigen Geräten beibehält.

Ich habe eine relativ saubere Lösung gefunden, die für mich in Ordnung war.

Im Thema verwende ich einen 9-Patch-Hintergrund, um eine benutzerdefinierte Hintergrundfarbe zu erhalten:

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

Ich habe den Versuch, die Textfarbe zu formatieren, aufgegeben und nur ein Spannable verwendet, um die Textfarbe für mein Element im Code festzulegen:

@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
quelle
funktioniert hervorragend für mein Problem mit der Verwendung des ActionBarSherlock Light-Themas auf einem Lebkuchengerät! Damit kann ich den Hintergrund des Optionsmenüs leicht in Hellgrau und die Textfarbe in Schwarz ändern (Symbole sind bereits schwarz wie in der ActionBar! Danke!
florianbaethge
12

So habe ich meine gelöst. Ich habe gerade die Hintergrundfarbe und die Textfarbe in Stilen angegeben. dh res> values> styles.xml Datei.

<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <item name="android:itemBackground">#ffffff</item>
    <item name="android:textColor">#000000</item>
</style>
Bukunmi
quelle
1
Textfarbe würde sich überall ändern
user3156040
Es ändert nur die Hintergrundfarbe der Elemente und das Layout der
Menüoptionen
10

Eine Sache zu beachten, dass ihr das Problem genau wie viele andere Beiträge überkompliziert! Alles, was Sie tun müssen, ist, zeichnbare Selektoren mit dem gewünschten Hintergrund zu erstellen und sie auf tatsächliche Elemente zu setzen. Ich habe nur zwei Stunden damit verbracht, Ihre Lösungen auszuprobieren (alle auf dieser Seite vorgeschlagen), und keine davon hat funktioniert. Ganz zu schweigen davon, dass es Unmengen von Fehlern gibt, die Ihre Leistung in den Try / Catch-Blöcken, die Sie haben, wesentlich verlangsamen.

Sowieso ist hier eine Menü-XML-Datei:

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

Jetzt in Ihrem 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>

Wenn Sie das nächste Mal über Kanada in den Supermarkt gehen, probieren Sie Google Maps!

Tropfen von Jupiter
quelle
Ich bin vollkommen einverstanden. Warum Android neu erfinden, wenn er =) bereits existiert?
Fredrik
Funktioniert super. Erstellen Sie eine Ebenenliste, die mit Ihrem Symbol und dem gewünschten Hintergrund gezeichnet werden kann. Das einzige Problem ist, dass ich nicht weiß, ob ich die Textfarbe ändern kann. Daher funktioniert nicht jede Hintergrundfarbe
Janusz
52
Schön, elegant und geht das Problem überhaupt nicht an.
Aea
1
Wenn ich mich nicht irre, ändert dies nur den Hintergrund für das Symbol, nicht den Menüpunkt selbst, der weiß bleibt.
Jrom
3
Dies ist keine Frage. Das ist völlig anders gedacht.
Kostadin
4
 <style name="AppThemeLight" parent="Theme.AppCompat.Light.NoActionBar">
    <item name="android:itemBackground">#000000</item>
</style>

Das funktioniert gut für mich

Bincy Baby
quelle
wie man die
Titelfarbe ändert
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;
                }
            });
        }
    }
Ursprünglicher Pappachan
quelle
3
Bitte tun Sie dies nicht: name.equalsIgnoreCase ("com.android.internal.view.menu.IconMenuItemView" Wie der Name eindeutig anzeigt, werden private Implementierungsdetails verwendet und können daher bei jedem Plattform-Update oder Gerät
beschädigt
1
IconMenuItemView ist die Klasse, die das Optionsmenü erstellt und steuert, das von der Basisklasse View abgeleitet ist. Diese Klasse stammt aus dem Android-Quellcode und ist seit mindestens API-Version 5 vorhanden. Ich kann nicht sehen, dass sie auf einem Plattform-Update oder Gerät kaputt geht.
Primal Pappachan
1
Sie können es nicht sehen, weil Sie die Zukunft nicht sehen können. Auch wenn es einen Weg gab, um sicher zu sein, ist es eine schlechte Praxis
HXCaine
Danke, das ist zur Not nützlich. Funktioniert jedoch nicht in besonderen Fällen, z. B. bei Elementen, die in onCreateOptionsMenu erstellt, aber in onPrepareOptionsMenu deaktiviert, später jedoch wieder aktiviert wurden.
HRJ
3

Danke Marcus! Es funktioniert reibungslos mit 2.3, indem einige Syntaxfehler behoben werden. Hier ist der feste Code

    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
quelle
1
Alles, was ich dafür bekomme: java.lang.IllegalStateException: Eine Fabrik wurde bereits auf diesem LayoutInflater
Bostone
Um es mit ActionBarSherlock und dem Kompatibilitätsframework arbeiten zu lassen und IllegalStateException zu vermeiden, lesen Sie diesen Trick 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;
        }
    });
}

Dies ist eine XML-Datei

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

Wenn Sie eine beliebige Farbe festlegen möchten, scheint dies ziemlich gut zu funktionieren androidx. Getestet auf KitKat und Pie. Setzen Sie dies in Ihre 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);
}

Hiermit wird die Farbe festgelegt android.widget.PopupWindow$PopupBackgroundView, die, wie Sie vielleicht vermutet haben, die Hintergrundfarbe zeichnet. Es gibt keine Überziehung und Sie können auch halbtransparente Farben verwenden.

Eichhörnchen
quelle