且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

更改弹出菜单的背景颜色

更新时间:2023-01-26 19:31:56

我对被接受的答案不满意,因为它并不能真正解释为什么未应用OPs自定义弹出样式-不仅仅是背景,还有诸如文本颜色之类的东西-所以我做了自己的实验.

重要的是要注意,由Toolbar创建的弹出窗口(具有菜单项时)与通过PopupMenu显示自己的弹出窗口之间存在差异.这些由不同的主题属性控制.另外,请注意有两个PopupMenu类: android.widget.PopupMenu android.support.v7.widget.PopupMenu ./p>

您需要为显式显示的PopupMenu设置样式的主题属性是android:popupMenuStylepopupMenuStyle.您可以通过几种选择来实现自定义样式的正确应用:

(1)在活动(或应用程序)的主题中使用android:popupMenuStyle

<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <!-- if using android.widget.PopupMenu -->
    <item name="android:popupMenuStyle">@style/PopupMenu</item>
    <!-- if using android.support.v7.widget.PopupMenu -->
    <item name="popupMenuStyle">@style/PopupMenu</item>
</style/>

<style name="PopupMenu" parent="ThemeOverlay.AppCompat.Dark">
    <item name="android:popupBackground">@color/popupBackground</item>
</style>

PopupMenu popup = new PopupMenu(this, anchorView);

请注意,您的布局文件中不需要任何额外内容.

(2)使用ContextThemeWrapper

<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <!-- nothing special -->
</style/>

<style name="CustomPopupTheme" parent="ThemeOverlay.AppCompat.Dark">
    <!-- if using android.widget.PopupMenu -->
    <item name="android:popupMenuStyle">@style/PopupMenu</item>
    <!-- if using android.support.v7.widget.PopupMenu -->
    <item name="popupMenuStyle">@style/PopupMenu</item>
</style>

<style name="PopupMenu" parent="ThemeOverlay.AppCompat.Dark">
    <item name="android:popupBackground">@color/popupBackground</item>
</style>

ContextThemeWrapper ctw = new ContextThemeWrapper(this, R.style.CustomPopupTheme);
PopupMenu popup = new PopupMenu(ctw, anchorView);

请注意,在构造ContextThemeWrapper时,如何不直接使用R.style.PopupMenu.这似乎有些round回,但是如果您希望将弹出式主题与活动或应用程序主题分开,则很有用(例如,也许只有一些弹出式窗口需要您的特殊主题).

(3)使用您的AppBarLayout上下文

<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <!-- nothing special -->
</style/>

<style name="AppBarOverlay" parent="ThemeOverlay.AppCompat.Light">
    <!-- if using android.widget.PopupMenu -->
    <item name="android:popupMenuStyle">@style/PopupMenu</item>
    <!-- if using android.support.v7.widget.PopupMenu -->
    <item name="popupMenuStyle">@style/PopupMenu</item>
</style>

<style name="PopupMenu" parent="ThemeOverlay.AppCompat.Dark">
    <item name="android:popupBackground">@color/popupBackground</item>
</style>

<style name="PopupOverlay" parent="ThemeOverlay.AppCompat.Dark">
    <!-- changes the background of the Toolbar's popup -->
    <item name="android:colorBackground">@color/popupBackground</item>
</style>


<android.support.design.widget.AppBarLayout
    android:id="@+id/appbar"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:theme="@style/AppBarOverlay">

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="?attr/colorPrimary"
        app:popupTheme="@style/PopupOverlay"/>

</android.support.design.widget.AppBarLayout>


AppBarLayout appBar = (AppBarLayout) findViewById(R.id.app_bar);
PopupMenu popup = new PopupMenu(appBar.getContext(), anchorView);

由于您已经为AppBar设置了主题叠加层,因此可以使用它来保存弹出主题引用.至少在当前布局下,这也适用于工具栏的上下文,尽管请注意,app:popupTheme在这里实际上并不相关,因为它会影响Toolbar的弹出窗口,而不影响您的PopupMenu.还要注意,这与上面的选项2有多相似,应该可以让您了解android:theme属性在幕后的作用;)

在我的实验中,android:itemBackground仅在以PopupOverlay样式代替android:colorBackground时才起作用.但是,***使用android:colorBackground,因为那样会更改弹出窗口的窗口颜色,而圆角和可选项目的突出显示/波纹保持不变.

NOTE: I have searched for an hour and tried all solutions already provided by ***.

I am studying theme overlays. I have made a sample app, which opens a popup menu on clicking an action bar icon. Here is my styles.xml

<resources>

    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>

    </style>

    <style name="AppTheme.NoActionBar">
        <item name="windowActionBar">false</item>
        <item name="windowNoTitle">true</item>
    </style>



    <style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Light">
        <item name="android:textColorPrimary">@color/colorAccent</item>
    </style>

    <style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Dark">
        <!-- added all to see which one will work.-->
        <item name="android:popupMenuStyle">@style/PopupMenu</item>
        <item name="android:itemBackground">@color/colorAccent</item>
        <item name="android:colorBackground">@color/colorAccent</item>

    </style>

    <style name="PopupMenu" parent="@android:style/Widget.PopupMenu">
        <item name="android:popupBackground">@color/colorAccent</item>
    </style>

</resources>

and here is my toolbar style.

   <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/AppTheme.AppBarOverlay">

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:popupTheme="@style/AppTheme.PopupOverlay"/>

    </android.support.design.widget.AppBarLayout>

I have set the popupTheme to the one I have in my styles.xml. Now I want to change the background color of popup menu, which is currently white.

Here is the code.

 @Override
    public boolean onOptionsItemSelected(MenuItem item) {

        if(item.getItemId() == R.id.standard_menu){
            showPopupMenu(item);
            return true;
        }
        return super.onOptionsItemSelected(item);
    }

    private void showPopupMenu(MenuItem item) {
        PopupMenu p = new PopupMenu(this, findViewById(item.getItemId()));
        p.inflate(R.menu.pop_menu);
        p.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
            @Override
            public boolean onMenuItemClick(MenuItem item) {
                Toast.makeText(MainActivity.this, "clicked.", Toast.LENGTH_SHORT).show();
                return true;
            }
        });
        p.show();
    }

I wasn't satisfied with the accepted answer since it doesn't really explain why the OPs custom popup style isn't being applied--not just the background, but also things like the text color--so I did my own experimentation.

It's important to note there is a difference between the popup created by the Toolbar (when it has menu items) and showing one yourself with PopupMenu. These are governed by different theme attributes. Also, be aware there are two PopupMenu classes: android.widget.PopupMenu, and android.support.v7.widget.PopupMenu.

The theme attribute you need to style PopupMenus you show explicitly is android:popupMenuStyle or popupMenuStyle. You have a few options to achieve proper application of your custom style:

(1) Use android:popupMenuStyle in the theme of the activity (or app)

<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <!-- if using android.widget.PopupMenu -->
    <item name="android:popupMenuStyle">@style/PopupMenu</item>
    <!-- if using android.support.v7.widget.PopupMenu -->
    <item name="popupMenuStyle">@style/PopupMenu</item>
</style/>

<style name="PopupMenu" parent="ThemeOverlay.AppCompat.Dark">
    <item name="android:popupBackground">@color/popupBackground</item>
</style>

PopupMenu popup = new PopupMenu(this, anchorView);

Note this requires nothing extra in your layout file.

(2) Use a ContextThemeWrapper

<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <!-- nothing special -->
</style/>

<style name="CustomPopupTheme" parent="ThemeOverlay.AppCompat.Dark">
    <!-- if using android.widget.PopupMenu -->
    <item name="android:popupMenuStyle">@style/PopupMenu</item>
    <!-- if using android.support.v7.widget.PopupMenu -->
    <item name="popupMenuStyle">@style/PopupMenu</item>
</style>

<style name="PopupMenu" parent="ThemeOverlay.AppCompat.Dark">
    <item name="android:popupBackground">@color/popupBackground</item>
</style>

ContextThemeWrapper ctw = new ContextThemeWrapper(this, R.style.CustomPopupTheme);
PopupMenu popup = new PopupMenu(ctw, anchorView);

Note how this doesn't use R.style.PopupMenu directly when constructing the ContextThemeWrapper. This seems a bit roundabout, but it's useful if you want to keep the popup theme separated from activity or app themes (perhaps only some popups need your special theme, for example).

(3) Use your AppBarLayout's Context

<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <!-- nothing special -->
</style/>

<style name="AppBarOverlay" parent="ThemeOverlay.AppCompat.Light">
    <!-- if using android.widget.PopupMenu -->
    <item name="android:popupMenuStyle">@style/PopupMenu</item>
    <!-- if using android.support.v7.widget.PopupMenu -->
    <item name="popupMenuStyle">@style/PopupMenu</item>
</style>

<style name="PopupMenu" parent="ThemeOverlay.AppCompat.Dark">
    <item name="android:popupBackground">@color/popupBackground</item>
</style>

<style name="PopupOverlay" parent="ThemeOverlay.AppCompat.Dark">
    <!-- changes the background of the Toolbar's popup -->
    <item name="android:colorBackground">@color/popupBackground</item>
</style>


<android.support.design.widget.AppBarLayout
    android:id="@+id/appbar"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:theme="@style/AppBarOverlay">

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="?attr/colorPrimary"
        app:popupTheme="@style/PopupOverlay"/>

</android.support.design.widget.AppBarLayout>


AppBarLayout appBar = (AppBarLayout) findViewById(R.id.app_bar);
PopupMenu popup = new PopupMenu(appBar.getContext(), anchorView);

Since you already have a theme overlay for the AppBar, you can use it to hold your popup theme references. This would also work with the Toolbar's context, at least given the current layout, although note that app:popupTheme is not actually relevant here since it affects the Toolbar's popup and not your PopupMenu. Also note how similar this is to option 2 above, which should clue you in to how the android:theme attribute works under the hood ;)

In my experiments, android:itemBackground only worked when I used it in place of android:colorBackground in the PopupOverlay style. However, it's better to use android:colorBackground because that will change the popup's window color, leaving the rounded corners and the selectable item highlight/ripple of the items intact.