【问题标题】:Change Popup menu background color更改弹出菜单背景颜色
【发布时间】:2016-11-18 07:31:27
【问题描述】:

注意:我已经搜索了一个小时并尝试了所有已经提供的解决方案 通过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 中的那个。现在我想更改当前为白色的弹出菜单的背景颜色。

这里是代码。

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

【问题讨论】:

标签: android android-layout themes android-toolbar android-theme


【解决方案1】:

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

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

需要明确显示PopupMenus 样式的主题属性是android:popupMenuStyle 或popupMenuStyle。您有几个选项可以正确应用您的自定义样式:

(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。这似乎有点迂回,但如果您想将弹出式主题与活动或应用程序主题分开(例如,也许只有一些弹出式需要您的特殊主题),它会很有用。

(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,因为这会改变弹出窗口的颜色,使圆角和可选项目高亮/波纹保持不变。

【讨论】:

    【解决方案2】:
    <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);
    

    可能对你有帮助

    【讨论】:

      【解决方案3】:

      我做到了,请检查是否有人有问题也将其添加到样式中

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

      popmenu的代码是

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

      【讨论】:

        【解决方案4】:

        这对我有用

        <item name="android:itemBackground">@color/primary</item>
        

        将其插入您的主要风格 我希望这对你有用

        【讨论】:

        • 是的。它有效,但为什么其他选项不起作用?
        • 我很困惑。 OP 中的图像表明没有应用整个弹出样式。 PopupOverlay 扩展ThemeOverlay.AppCompat.Dark,所以文本颜色应该是浅色的,但显然不是。这可能只解决弹出窗口的背景问题,但并不能真正回答为什么没有应用定义的自定义样式。
        【解决方案5】:

        在支持 v7 库中为 PopupMenu 使用“popupMenuStyle”,并且 对常规 PopupMenu 使用“android:popupMenuStyle”

        【讨论】:

          【解决方案6】:

          以上解决方案都不适合我,所以我就是这样解决的:

          首先为Activity创建一个新主题,然后:

          <style name="Theme.YourTheme" parent="Theme.AppCompat">
              <item name="android:itemBackground">@color/white</item>
              <item name="android:textColor">@color/black</item>
          </style>
          
          1. 使项目的背景变白

            <item name="android:itemBackground">@color/white</item>
            
          2. 反制使文本颜色变黑

            <item name="android:textColor">@color/black</item>
            

          最后,通过 Manifest 将主题应用到您的 Activity:

              <activity android:name=".YourActivity"
                  android:theme="@style/Theme.YourTheme"/>
          

          【讨论】:

            【解决方案7】:

            试试看

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

            【讨论】:

              【解决方案8】:

              要删除在 AndroidX 中添加的边距:

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

              【讨论】:

                【解决方案9】:

                ANDROIDMAINFEST.xml 中无需做任何更改

                感谢shekhar's answer##

                结帐

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

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

                方法

                 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 适配器中完成的

                希望你喜欢它。

                代码也是不言自明的。

                【讨论】:

                • 正如目前所写,您的答案尚不清楚。请edit 添加其他详细信息,以帮助其他人了解这如何解决所提出的问题。你可以找到更多关于如何写好答案的信息in the help center。
                【解决方案10】:

                将 popupMenu 样式添加到您的 AppTheme:

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

                我希望它会起作用。

                【讨论】:

                  【解决方案11】:

                  尝试像这样在 PopupOverlay 中使用 colorPrimary

                  <style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" >
                      <item name="colorPrimary">@color/blue_ivy</item>
                  </style>
                  

                  【讨论】:

                    【解决方案12】:

                    使用 AppCompat 工具栏中的 popupTheme

                     <android.support.v7.widget.Toolbar
                            android:id="@+id/toolbar"
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            app:popupTheme="@style/MyTheme"/>
                    

                    风格:

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

                    希望它会起作用。

                    【讨论】:

                      猜你喜欢
                      • 2016-03-16
                      • 1970-01-01
                      • 2014-02-09
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 2015-04-06
                      • 1970-01-01
                      相关资源
                      最近更新 更多