更改弹出菜单的背景颜色

17

注意: 我已经搜索了一个小时并尝试了stackoverflow提供的所有解决方案。

我正在学习主题覆盖。我制作了一个示例应用程序,单击操作栏图标会打开弹出菜单。这是我的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>

这是我的工具栏样式。

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

我已将popupTheme设置为我在styles.xml中拥有的主题。现在我想更改弹出菜单的背景颜色,当前为白色。

enter image description here

以下是代码:

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

你尝试过使用<item name="popupMenuStyle">@style/PopupMenu</item>吗? - Karakuri
是的。不起作用。 - mallaudin
请查看此处:http://www.silverbaytech.com/2013/05/27/themes-for-the-android-actionbar-actionbaritems/ - Manikandan K
@ManikandanK,我为什么要使用Theme.Sherlock?它已经过时了。 - mallaudin
请参考此处:http://www.grokkingandroid.com/migrating-actionbarsherlock-actionbarcompat/ - Manikandan K
显示剩余3条评论
12个回答

48

我对已接受的答案不满意,因为它没有真正解释为什么 OP 的自定义弹出窗口样式没有被应用,不仅是背景,还包括文本颜色,所以我进行了自己的实验。

需要注意的是,Toolbar 创建的弹出窗口(当它有菜单项时)和使用 PopupMenu 自己显示的弹出窗口之间存在区别。这些由不同的主题属性控制。此外,请注意有两个 PopupMenu 类: android.widget.PopupMenuandroid.support.v7.widget.PopupMenu

您需要对显式显示的 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);
请注意,这不需要在您的布局文件中添加任何额外内容。
使用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。这似乎有点绕,但如果您想将弹出主题与活动或应用程序主题分开(例如,仅某些弹出需要您的特殊主题),则非常有用。

(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创建了主题覆盖,因此可以使用它来容纳您的弹出主题引用。就当前的布局而言,这也适用于Toolbar的上下文,但请注意,app:popupTheme在这里实际上没有关联作用,因为它会影响到Toolbar的弹出窗口而不是您的PopupMenu。还请注意,这与上述选项2有多么相似,这应该让您了解android:theme属性在内部是如何工作的 ;)

在我的实验中,只有当我将android:itemBackground用于PopupOverlay样式中android:colorBackground的位置时,它才起作用。然而,最好使用android:colorBackground,因为这将改变弹出窗口的窗口颜色,保留项目的圆角和可选择项高亮/涟漪效果。


这是我一直在网上寻找的答案,当然它出现在互联网的最后一页!哈哈。谢谢! - JPM

7
<style name="YOURSTYLE" parent="Widget.AppCompat.PopupMenu">
    <item name="android:textColor">@android:color/white</item>
    <item name="android:itemBackground">@android:color/holo_red_light</item>
</style>

Context wrapper = new ContextThemeWrapper(this, R.style.YOURSTYLE);
PopupMenu popup = new PopupMenu(wrapper, view);

也许这能帮上你的忙。

4

我完成了,请检查一下,如果有人遇到问题,也请将其添加到样式中。

 <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/appGreenColor</item>
</style>

弹出菜单的代码如下:

 private void openPopMenuList(View view) {
    //custom background COlor view
    PopupMenu popup = new PopupMenu(new ContextThemeWrapper(getActivity(), R.style.CustomPopupTheme), view);
    try {
        // Reflection apis to enforce show icon
        Field[] fields = popup.getClass().getDeclaredFields();
        for (Field field : fields) {
            if (field.getName().equals( POPUP_CONSTANT )) {
                field.setAccessible( true );
                Object menuPopupHelper = field.get( popup );
                Class<?> classPopupHelper = Class.forName( menuPopupHelper.getClass().getName() );
                Method setForceIcons = classPopupHelper.getMethod( POPUP_FORCE_SHOW_ICON, boolean.class );
                setForceIcons.invoke( menuPopupHelper, true );
                break;
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
    popup.getMenuInflater().inflate( R.menu.pop_up_menu, popup.getMenu() );
    popup.setOnMenuItemClickListener( this );
    popup.show();


}

以下是弹出菜单项:
<?xml version="1.0" encoding="utf-8"?>

<item
    android:id="@+id/share_popmenu"
    android:icon="@drawable/menu_share"
    android:title="@string/share_with_friends" />


<item
    android:id="@+id/askdelete_popmenu"
    android:icon="@drawable/menu_delete"
    android:title="Ask For Delete" />


3
这对我有用。
<item name="android:itemBackground">@color/primary</item>

将其插入到您的主要样式中。 希望这对您有用。


是的,它可以工作,但为什么其他选项不起作用呢? - mallaudin
1
我有些困惑。原帖中的图片表明整个弹出式样式并未被应用。PopupOverlay 扩展了 ThemeOverlay.AppCompat.Dark,因此文本颜色应该是浅色的,但显然不是这样。这可能只解决了弹出窗口的背景问题,但并没有真正回答为什么自定义样式没有被应用。 - Karakuri

2
在支持 v7 库中,可以使用“popupMenuStyle”来设置弹出式菜单的样式;对于普通的 PopupMenu,则需要使用“android:popupMenuStyle”。请注意保留 HTML 标签。

2

试一试

<style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light">
        <item name="android:colorBackground">@color/white</item>
        <item name="android:textColor">@color/grey_900</item>
    </style>

1

以上解决方案都对我无效,这是我修复它的方法:

首先为活动创建一个新主题,并执行以下操作:

<style name="Theme.YourTheme" parent="Theme.AppCompat">
    <item name="android:itemBackground">@color/white</item>
    <item name="android:textColor">@color/black</item>
</style>
  1. To make the background of items white

    <item name="android:itemBackground">@color/white</item>
    
  2. To counter make the text color black

    <item name="android:textColor">@color/black</item>
    
最后,通过清单将主题应用于您的活动:
    <activity android:name=".YourActivity"
        android:theme="@style/Theme.YourTheme"/>

1

要移除 AndroidX 中添加的边距:

PopupMenu popup = new PopupMenu(this, my_button, 0, 0, 0);

1

不需要更改ANDROIDMAINFEST.xml文件

感谢Shekhar的回答##

查看此内容

您可以通过在片段或活动中提供或掩盖自定义主题来实现它,并在创建自定义主题后将该上下文传递给弹出菜单。 首先,在菜单中创建弹出菜单布局。

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <item
        android:id="@+id/remove"
        android:title="Remove downloads"

        />
</menu>

在style.xml中进行第二种样式设置。
 <style name="CustomPopUpStyle" parent="Widget.AppCompat.PopupMenu">
    <item name="android:textColor">@android:color/white</item>
    <item name="android:itemBackground">@color/bgColor</item>
</style>
 

method

 private fun showPopupMenu(context: Context, view: View) {
        var wrapper: Context =  ContextThemeWrapper(context, R.style.CustomPopUpStyle)
        val popup = PopupMenu(wrapper, view)
        popup.inflate(R.menu.popup_menu)
        popup.setOnMenuItemClickListener(PopupMenu.OnMenuItemClickListener { item: MenuItem? ->
            when (item!!.itemId) {
                R.id.remove -> {
                    Toast.makeText(context, item.title, Toast.LENGTH_SHORT).show()
                }
            }

            true
        })

        popup.show()
    }

最后初始化。
 showPopupMenu(holder.itemView.context, holder.viewDataBinding.more)

我在片段中的RecyclerView适配器中完成了这个操作。

希望你喜欢。

代码也很容易理解。


1
目前你的回答不够清晰,请 [编辑] 添加更多细节,以帮助其他人了解如何解决所提出的问题。您可以在帮助中心中找到有关如何撰写良好答案的更多信息。 - Community

0
在您的AppTheme中添加popupMenu样式:
<style name="AppTheme" parent="android:Theme.Light">
    <item name="android:popupMenuStyle">@style/PopupMenu</item>
</style>

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

manifest.xml:

 <application
    android:allowBackup="true"
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/AppTheme" >
.............
</application>

我希望它能够正常工作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接