Bagaimana cara mengubah warna latar belakang dari menu opsi?

96

Saya mencoba mengubah warna default untuk menu opsi yang putih: Saya ingin latar belakang hitam untuk setiap item di menu opsi.

Saya telah mencoba beberapa pemotretan seperti android: itemBackground = "# 000000" pada elemen item dalam elemen menu tetapi tidak berhasil.

Bagaimana saya bisa melakukannya?

feragusper
sumber

Jawaban:

65

Setelah menghabiskan cukup banyak waktu untuk mencoba semua opsi, satu-satunya cara saya bisa mendapatkan aplikasi menggunakan AppCompat v7 untuk mengubah latar belakang menu tambahan adalah menggunakan atribut itemBackground:

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

Diuji dari API 4.2 hingga 5.0.

TheIT
sumber
2
Ini harus menjadi jawaban yang diterima, mudah dan sederhana.
Alex Ardavin
3
Tapi ini menghilangkan efek riak: / Pokoknya harus mengembalikannya?
David Velasquez
Saya ingin mengubah seluruh latar belakang jendela, bukan memisahkan latar belakang item, misalnya akan menambahkan batas ke setiap item jika Anda menyetel latar belakang seperti itu (dengan batas) ...
user25
1
Bagaimana dengan warna teks menu?
doctorram
51

Ini jelas merupakan masalah yang dihadapi banyak pemrogram dan Google belum memberikan solusi yang didukung dan memuaskan.

Ada banyak niat silang dan kesalahpahaman yang beredar di sekitar postingan tentang topik ini, jadi harap baca seluruh jawaban ini sebelum menanggapi.

Di bawah ini saya menyertakan versi peretasan yang lebih "halus" dan dikomentari dengan baik dari jawaban lain di laman ini, juga menggabungkan gagasan dari pertanyaan yang sangat terkait ini:

Ubah warna latar belakang menu android

Bagaimana cara mengubah warna latar belakang dari menu opsi?

Android: sesuaikan menu aplikasi (mis. Warna latar belakang)

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

Tombol Toggle Item Menu Android

Apakah mungkin membuat latar belakang menu opsi Android tidak tembus cahaya?

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

Menyetel latar belakang menu menjadi buram

Saya menguji peretasan ini pada 2.1 (simulator), 2.2 (2 perangkat nyata), dan 2.3 (2 perangkat nyata). Saya belum memiliki tablet 3.X untuk diuji, tetapi akan memposting perubahan yang diperlukan di sini jika / jika saya melakukannya. Mengingat bahwa tablet 3.X menggunakan Bilah Tindakan alih-alih Menu Opsi, seperti yang dijelaskan di sini:

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

Peretasan ini hampir pasti tidak akan melakukan apa pun (tidak merugikan dan tidak berguna) pada tablet 3.X.

PERNYATAAN MASALAH (baca ini sebelum membalas pemicu dengan komentar negatif):

Menu Opsi memiliki gaya yang sangat berbeda pada perangkat yang berbeda. Hitam murni dengan teks putih di beberapa, putih bersih dengan teks hitam di beberapa. Saya dan banyak pengembang lain ingin mengontrol warna latar belakang sel menu Opsi serta warna teks menu Opsi .

Pengembang aplikasi tertentu hanya perlu menyetel warna latar belakang sel (bukan warna teks), dan mereka dapat melakukannya dengan cara yang lebih rapi menggunakan gaya android: panelFullBackground yang dijelaskan dalam jawaban lain. Namun, saat ini tidak ada cara untuk mengontrol warna teks menu Opsi dengan gaya, sehingga seseorang hanya dapat menggunakan metode ini untuk mengubah latar belakang ke warna lain yang tidak akan membuat teks "menghilang".

Kami akan senang melakukan ini dengan solusi terdokumentasi, bukti masa depan, tetapi satu tidak tersedia pada Android <= 2.3. Jadi kita harus menggunakan solusi yang berfungsi di versi saat ini dan dirancang untuk meminimalkan kemungkinan rusak / rusak di versi mendatang. Kami menginginkan solusi yang gagal dengan anggun kembali ke perilaku default jika harus gagal.

Ada banyak alasan yang sah mengapa seseorang mungkin perlu mengontrol tampilan menu Opsi (biasanya agar sesuai dengan gaya visual untuk sisa aplikasi) jadi saya tidak akan memikirkannya.

Ada bug Google Android yang diposting tentang ini: harap tambahkan dukungan Anda dengan memberi bintang pada bug ini (catatan Google melarang komentar "saya juga": cukup bintang saja):

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

RINGKASAN SOLUSI JAUH:

Beberapa poster menyarankan peretasan yang melibatkan LayoutInflater.Factory. Peretasan yang disarankan berfungsi untuk Android <= 2.2 dan gagal untuk Android 2.3 karena peretasan tersebut membuat asumsi yang tidak terdokumentasi: bahwa seseorang dapat memanggil LayoutInflater.getView () secara langsung tanpa saat ini berada di dalam panggilan ke LayoutInflater.inflate () pada instance LayoutInflater yang sama. Kode baru di Android 2.3 mematahkan asumsi ini dan menyebabkan NullPointerException.

Peretasan saya yang sedikit halus di bawah ini tidak bergantung pada asumsi ini.

Selain itu, peretasan juga mengandalkan penggunaan nama kelas internal yang tidak terdokumentasi "com.android.internal.view.menu.IconMenuItemView" sebagai string (bukan sebagai tipe Java). Saya tidak melihat cara untuk menghindari ini dan masih mencapai tujuan yang dinyatakan. Namun, Anda dapat melakukan peretasan dengan hati-hati yang akan mundur jika "com.android.internal.view.menu.IconMenuItemView" tidak muncul di sistem saat ini.

Sekali lagi, pahami bahwa ini adalah peretasan dan saya tidak mengklaim ini akan berfungsi di semua platform. Tapi kami para pengembang tidak hidup dalam dunia akademis fantasi di mana segala sesuatu harus sesuai dengan buku: kami memiliki masalah yang harus diselesaikan dan kami harus menyelesaikannya sebaik mungkin. Misalnya, "com.android.internal.view.menu.IconMenuItemView" tampaknya tidak mungkin ada di tablet 3.X karena mereka menggunakan Bilah Tindakan dan bukan Menu Opsi.

Akhirnya, beberapa pengembang telah memecahkan masalah ini dengan sepenuhnya menekan Menu Opsi Android dan menulis kelas menu mereka sendiri (lihat beberapa tautan di atas). Saya belum mencoba ini, tetapi jika Anda punya waktu untuk menulis Tampilan Anda sendiri dan mencari cara untuk mengganti tampilan Android (saya yakin iblis ada dalam detail di sini) maka itu mungkin solusi yang bagus yang tidak memerlukan peretasan tidak berdokumen.

HACK:

Ini kodenya.

Untuk menggunakan kode ini, panggil addOptionsMenuHackerInflaterFactory () ONCE dari aktivitas Anda onCreate () atau aktivitas Anda onCreateOptionsMenu (). Ini menetapkan pabrik default yang akan mempengaruhi pembuatan Menu Opsi selanjutnya. Ini tidak memengaruhi Menu Opsi yang telah dibuat (peretasan sebelumnya menggunakan nama fungsi setMenuBackground (), yang sangat menyesatkan karena fungsi tersebut tidak menyetel properti menu apa pun sebelum dikembalikan).

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

Terimakasih telah membaca dan semoga bisa menikmati!

Louis Semprini
sumber
15
Satu-satunya hal yang dapat saya andalkan saat mencoba menggunakan ini (dan solusi serupa) adalah `java.lang.IllegalStateException: Sebuah pabrik telah disetel di LayoutInflater`
Bostone
Bekerja untuk saya! Senang sekali akhirnya punya solusi! Diuji pada Gingerbread, Honeycomb dan ICS
Chad Schultz
Diuji di Samsung Galaxy Nexus (4.1.1) dan berfungsi! Barang bagus, Louis!
Felipe Caldas
2
Berfungsi pada Galaxy Nexus 7 (4.1.1) namun warna teks dikembalikan untuk setiap panggilan berikutnya ke menu setelah disembunyikan untuk pertama kalinya.
Will Kru
1
Saya juga mendapatkan IllegalStateException. Sepertinya peretasan tersebut tidak kompatibel dengan ActionBarSherlock, yang saya gunakan.
Travis
20

Atribut gaya untuk latar belakang menu adalah android:panelFullBackground.

Terlepas dari apa yang dikatakan dalam dokumentasinya, ia harus berupa sumber daya (misalnya @android:color/blackatau @drawable/my_drawable), ia akan macet jika Anda menggunakan nilai warna secara langsung.

Ini juga akan menghilangkan batas item yang tidak dapat saya ubah atau hapus menggunakan solusi primalpop.

Sedangkan untuk warna teks, saya belum menemukan cara untuk mengaturnya melalui gaya di 2.2 dan saya yakin saya sudah mencoba semuanya (begitulah cara saya menemukan atribut latar belakang menu). Anda perlu menggunakan solusi primalpop untuk itu.

Pilot_51
sumber
3
Di mana saya harus menyetel nilai ini? Saya tidak bisa membuatnya berfungsi di Android 2.2. atau 2.3
Janusz
1
@JanusDi Styles. Ini mungkin akan membantu: developer.android.com/guide/topics/resources/…
Pilot_51
2
Tidak berfungsi, bagus jika Anda dapat menyatakan ke mana seharusnya pergi, mencoba di mana-mana kecuali untuk membuat gaya lain untuk item menu saya untuk atribut .....
John
14

Untuk Android 2.3, ini dapat dilakukan dengan beberapa peretasan yang sangat berat:

Penyebab utama masalah Android 2.3 adalah di LayoutInflater, mConstructorArgs [0] = mContext hanya disetel selama menjalankan panggilan ke

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

Saya mengujinya untuk bekerja pada Android 2.3 dan masih bekerja pada versi sebelumnya. Jika ada yang rusak lagi di versi Android selanjutnya Anda hanya akan melihat gaya menu default sebagai gantinya

Marcus Wolschon
sumber
Kode ini hanya berjalan hingga versi 2.1. Kode di sini tampaknya lebih baik: stackoverflow.com/questions/2944244/…
Felipe Caldas
Hai, Saya telah menggunakan fungsi Anda tetapi saya mendapat kesalahan berikut ini Kesalahan menggembungkan kelas com.android.internal.view.menu.IconMenuItemView dan kemudian satu pengecualian lagi Kesalahan menggembungkan kelas <unknown> ... sekarang apa yang harus saya lakukan sekarang ... ? tolong bantu aku.
Rushabh Patel
13

Baru saja mengalami masalah ini juga, pada Aplikasi yang harus kompatibel dengan Gingerbread dan masih mempertahankan sebanyak mungkin gaya dari perangkat yang mendukung Holo.

Saya menemukan solusi yang relatif bersih, yang berfungsi baik untuk saya.

Dalam tema, saya menggunakan latar belakang drawable 9-patch untuk mendapatkan warna latar kustom:

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

Saya berhenti mencoba memberi gaya pada warna teks, dan hanya menggunakan Spannable untuk mengatur warna teks untuk item saya dalam kode:

@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
sumber
berfungsi dengan baik untuk masalah saya dengan menggunakan tema ActionBarSherlock Light pada perangkat Gingerbread! Dengan ini, saya dapat dengan mudah mengubah latar belakang menu opsi menjadi abu-abu muda dan warna teks menjadi hitam (Ikon sudah berwarna hitam seperti di ActionBar! Terima kasih!
florianbaethge
13

Beginilah cara saya memecahkan masalah saya. Saya baru saja menentukan warna latar belakang dan warna teks dalam gaya. yaitu res> nilai> file styles.xml.

<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <item name="android:itemBackground">#ffffff</item>
    <item name="android:textColor">#000000</item>
</style>
Bukunmi
sumber
1
textcolor akan berubah di mana
user3156040
itu hanya mengubah warna latar belakang item, dan tata letak opsi menu memiliki bantalan atas dan bawah, itu tidak membantu
FarshidABZ
10

Satu hal yang perlu diperhatikan bahwa kalian terlalu memperumit masalah seperti banyak pos lainnya! Yang perlu Anda lakukan adalah membuat pemilih yang dapat digambar dengan latar belakang apa pun yang Anda butuhkan dan mengaturnya ke item sebenarnya. Saya hanya menghabiskan dua jam mencoba solusi Anda (semua disarankan di halaman ini) dan tidak ada yang berhasil. Belum lagi ada banyak kesalahan yang pada dasarnya memperlambat kinerja Anda dalam blok coba / tangkap yang Anda miliki.

Anyways di sini adalah file menu 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>

Sekarang di item1_selector Anda:

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

Lain kali Anda memutuskan untuk pergi ke supermarket melalui Kanada, coba peta google!

tetesOfJupiter
sumber
Saya sangat setuju. Mengapa menemukan kembali Android ketika dia =) sudah ada?
Fredrik
Bekerja dengan baik. Buat daftar lapisan yang dapat digambar dengan ikon Anda dan latar belakang yang diinginkan. Satu-satunya masalah adalah saya tidak tahu apakah saya bisa mengubah warna teks. Oleh karena itu, tidak semua warna latar belakang berfungsi
Janusz
52
Cantik, elegan, dan sama sekali tidak mengatasi masalah tersebut.
Aea
1
Jika saya tidak salah, ini hanya mengubah latar belakang ikon, bukan item menu itu sendiri, yang tetap putih.
Jrom
3
Ini bukan pertanyaan. Ini benar-benar pemikiran yang berbeda.
Kostadin
4
 <style name="AppThemeLight" parent="Theme.AppCompat.Light.NoActionBar">
    <item name="android:itemBackground">#000000</item>
</style>

ini bekerja dengan baik untuk saya

Bincy Baby
sumber
cara mengubah warna judul
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
sumber
3
Harap jangan lakukan ini: name.equalsIgnoreCase ("com.android.internal.view.menu.IconMenuItemView" Seperti yang ditunjukkan dengan jelas oleh namanya, ini menggunakan detail implementasi pribadi, dan dengan demikian dapat merusak pembaruan platform atau perangkat apa pun.
hackbod
1
IconMenuItemView adalah kelas yang membuat dan mengontrol menu opsi yang diturunkan dari kelas View dasar. Kelas ini berasal dari kode sumber android dan telah ada setidaknya sejak api versi 5. Saya tidak bisa melihatnya melanggar di pembaruan platform atau perangkat apa pun.
Primal Pappachan
1
Anda tidak dapat melihatnya karena Anda tidak dapat melihat masa depan. Bahkan jika ada cara untuk memastikan, itu praktik yang buruk
HXCaine
Terima kasih, ini berguna dalam keadaan darurat. Namun, tidak berfungsi dalam kasus khusus, seperti, item yang dibuat di onCreateOptionsMenu, tetapi dinonaktifkan di onPrepareOptionsMenu, tetapi kemudian diaktifkan lagi.
HRJ
3

Terima kasih Marcus! Ini berfungsi pada 2.3 dengan lancar dengan memperbaiki beberapa kesalahan sintaks, inilah kode yang diperbaiki

    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
sumber
1
Yang saya dapatkan untuk ini: java.lang.IllegalStateException: Sebuah pabrik telah ditetapkan pada LayoutInflater ini
Bostone
untuk membuatnya bekerja dengan ActionBarSherlock dan kerangka kerja kompatibilitas dan menghindari IllegalStateException lihat trik ini 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;
        }
    });
}

ini adalah file XML

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

Jika Anda ingin menetapkan warna sewenang-wenang, ini tampaknya berfungsi dengan baik androidx. Diuji di KitKat dan Pie. Masukkan ini ke dalam 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);
}

Ini mengatur warna android.widget.PopupWindow$PopupBackgroundView, yang, seperti yang mungkin sudah Anda duga, akan menggambar warna latar belakang. Tidak ada penarikan berlebih dan Anda juga dapat menggunakan warna semi transparan.

tupai
sumber