问题描述
注意:我已经搜索了一个小时并尝试了所有已经提供的解决方案通过stackoverflow.
我正在研究主题叠加.我制作了一个示例应用程序,它会在单击操作栏图标时打开一个弹出菜单.这是我的 styles.xml
<!-- 基本应用程序主题.--><style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar"><!-- 在此处自定义您的主题.--><item name="colorPrimary">@color/colorPrimary</item><项目名称="colorPrimaryDark">@color/colorPrimaryDark</item><item name="colorAccent">@color/colorAccent</item></风格><style name="AppTheme.NoActionBar"><item name="windowActionBar">false</item><item name="windowNoTitle">true</item></风格><style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Light"><item name="android:textColorPrimary">@color/colorAccent</item></风格><style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Dark"><!-- 添加所有内容以查看哪个有效.--><item name="android:popupMenuStyle">@style/PopupMenu</item><item name="android:itemBackground">@color/colorAccent</item><item name="android:colorBackground">@color/colorAccent</item></风格><style name="PopupMenu" parent="@android:style/Widget.PopupMenu"><item name="android:popupBackground">@color/colorAccent</item></风格></资源>
这是我的工具栏样式.
这是代码.
@Override公共布尔 onOptionsItemSelected(MenuItem item) {if(item.getItemId() == R.id.standard_menu){显示弹出菜单(项目);返回真;}返回 super.onOptionsItemSelected(item);}私人无效 showPopupMenu(MenuItem item) {PopupMenu p = new PopupMenu(this, findViewById(item.getItemId()));p.inflate(R.menu.pop_menu);p.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {@覆盖public boolean onMenuItemClick(MenuItem item) {Toast.makeText(MainActivity.this, "clicked.", Toast.LENGTH_SHORT).show();返回真;}});p.show();}
解决方案 我对接受的答案并不满意,因为它并没有真正解释为什么没有应用 OP 自定义弹出样式——而不仅仅是背景,还有文字颜色之类的东西——所以我做了我自己的实验.
请务必注意,Toolbar
创建的弹出窗口(当它有菜单项时)与使用 PopupMenu
显示自己的弹出窗口之间存在差异.这些由不同的主题属性控制.另外,请注意有两个 PopupMenu
类:android.widget.PopupMenu
和 android.support.v7.widget.PopupMenu
.
您需要为您显式显示的 PopupMenu
设置样式的主题属性是 android:popupMenuStyle
或 popupMenuStyle
.您有几个选项可以正确应用您的自定义样式:
(1)在活动(或应用)的主题中使用android:popupMenuStyle
<!-- 如果使用 android.widget.PopupMenu --><item name="android:popupMenuStyle">@style/PopupMenu</item><!-- 如果使用 android.support.v7.widget.PopupMenu --><item name="popupMenuStyle">@style/PopupMenu</item></风格/><style name="PopupMenu" parent="ThemeOverlay.AppCompat.Dark"><item name="android:popupBackground">@color/popupBackground</item></风格>PopupMenu popup = new PopupMenu(this, anchorView);
请注意,这不需要在您的布局文件中添加任何额外内容.
(2) 使用 ContextThemeWrapper
<!-- 没什么特别的--></风格/><style name="CustomPopupTheme" parent="ThemeOverlay.AppCompat.Dark"><!-- 如果使用 android.widget.PopupMenu --><item name="android:popupMenuStyle">@style/PopupMenu</item><!-- 如果使用 android.support.v7.widget.PopupMenu --><item name="popupMenuStyle">@style/PopupMenu</item></风格><style name="PopupMenu" parent="ThemeOverlay.AppCompat.Dark"><item name="android:popupBackground">@color/popupBackground</item></风格>ContextThemeWrapper ctw = new ContextThemeWrapper(this, R.style.CustomPopupTheme);PopupMenu popup = new PopupMenu(ctw, anchorView);
请注意,在构造 ContextThemeWrapper
时,它如何不直接使用 R.style.PopupMenu
.这似乎有点迂回,但如果您想将弹出主题与活动或应用主题分开(例如,也许只有某些弹出窗口需要您的特殊主题),它会很有用.
(3) 使用 AppBarLayout
的上下文
<!-- 没什么特别的--></风格/><style name="AppBarOverlay" parent="ThemeOverlay.AppCompat.Light"><!-- 如果使用 android.widget.PopupMenu --><item name="android:popupMenuStyle">@style/PopupMenu</item><!-- 如果使用 android.support.v7.widget.PopupMenu --><item name="popupMenuStyle">@style/PopupMenu</item></风格><style name="PopupMenu" parent="ThemeOverlay.AppCompat.Dark"><item name="android:popupBackground">@color/popupBackground</item></风格><style name="PopupOverlay" parent="ThemeOverlay.AppCompat.Dark"><!-- 改变工具栏弹出窗口的背景--><item name="android:colorBackground">@color/popupBackground</item></风格><android.support.design.widget.AppBarLayoutandroid:id="@+id/appbar"android:layout_width="match_parent"android:layout_height="wrap_content"android:theme="@style/AppBarOverlay"><android.support.v7.widget.Toolbarandroid:id="@+id/工具栏"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
因为这会改变弹出窗口的窗口颜色,使圆角和项目的可选项目高亮/波纹完好无损.
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 PopupMenu
s 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.
这篇关于更改弹出菜单背景颜色的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!