Android修改ActionBar二级菜单的外形,以及上下文菜单样式

文章讲述了如何根据老板的需求,修改Android应用中ActionBar的二级菜单和上下文菜单样式,从查找theme属性、AOSP源码分析,到最后成功自定义popupBackground和actionOverflowMenuStyle的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Android修改ActionBar二级菜单的外形,以及上下文菜单样式

原因:老板不喜欢android菜单那种方方正正的弹出框,所以要求修改弹出框的样式为圆角的。

我也是第一次去修改,就在网上找了类似的文章研究。发现基本上都是修改个底色就没了,并没有修改到形状。根据我上一次修改Alertdialog的外观一个逻辑,就是去找theme主要中的属性,看看有没有可以修改到的二级菜单和上下文菜单的属性,对应添加就行。
对于这种修改,是需要翻android源码的。因为现在本人在做这方面的工作,所以对安卓修改的自由度更大。如果小伙伴只是单纯的开发app,但是想要自己的UI更加个性、高度的自定义。我强烈建议去拉一个AOSP源码,否则对于一些theme参数里包含的style,app开发者是看不见的。也就是黑盒去各种试,很折磨人

<style name="templateTheme" parent="@android:style/Theme.Material.Light">
	<item name="内部属性">你自定义的值</item>
</style>

向这里的Theme.Material.Light,定义在frameworks/base/core/res/res/values/themes_material.xml(PS:这个是AOSP源码的东西,如果不想下载源码的话,只能在google上找themes_material.xml源码内容,google有提供Android Source)

<style name="Theme.Material.Light" parent="Theme.Light">
        <item name="colorForeground">@color/foreground_material_light</item>
        <item name="colorForegroundInverse">@color/foreground_material_dark</item>
        <item name="colorBackground">@color/background_material_light</item>
        <item name="colorBackgroundFloating">@color/background_floating_material_light</item>
        <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_material_light</item>
        <item name="disabledAlpha">@dimen/disabled_alpha_material_light</item>
        <item name="primaryContentAlpha">@dimen/primary_content_alpha_material_light</item>
        <!-- Text styles -->
        .....
        <!-- Button styles -->
        .....
        <!-- List attributes -->
        .....
</style>

可以看到这里面包含很多可以自定义的地方。我们要修改上下文菜单和actionBar的弹出菜单,所以我们去找对应的地方,上下文菜单即context menu,通过查找,可以找到这个属性

<item name="contextPopupMenuStyle">@style/Widget.Material.ContextPopupMenu</item>

之后,我们查找这个属性Widget.Material.ContextPopupMenu,位于frameworks/base/core/res/res/values/styles_material.xml中

<style name="Widget.Material.ContextPopupMenu" parent="Widget.Material.ListPopupWindow">
        <item name="overlapAnchor">true</item>
    </style>

发现Widget.Material.ContextPopupMenu这个继承Widget.Material.ListPopupWindow,去找Widget.Material.ListPopupWindow

<style name="Widget.Material.ListPopupWindow">
        <item name="dropDownSelector">?attr/listChoiceBackgroundIndicator</item>
        <item name="popupBackground">@drawable/popup_background_material</item>
        <item name="popupElevation">@dimen/floating_window_z</item>
        <item name="popupAnimationStyle">@empty</item>
        <item name="popupEnterTransition">@transition/popup_window_enter</item>
        <item name="popupExitTransition">@transition/popup_window_exit</item>
        <item name="dropDownVerticalOffset">0dip</item>
        <item name="dropDownHorizontalOffset">0dip</item>
        <item name="dropDownWidth">wrap_content</item>
    </style>

这里就是我们能够修改可以其作用的地方了,可以修改的都有类型定义。按照自己所需的自定义就好。我这里是修改了popupBackground,可以看到是一个drawable属性,所以就可以如下修改

<style name="templateTheme" parent="@android:style/Theme.Material.Light">
	<item name="@android:popupBackground">@drawable/你自己定义drawable文件名</item>
</style>

这样就可以修改上下文菜单的样式了。
那么,actionbar的二级菜单也是这样修改的,只不过并不想这样的简单。要想修改二级菜单,我们就得翻源码了。当然,我也是试错过。先介绍错误实验吧。

<!--第一个属性修改之后,并没有什么用-->
<item name="popupMenuStyle">@style/Widget.Material.Light.PopupMenu</item>
<!--第二个属性,可以看到为空,说明我们可以高度的自定义,我这里是直接配置的-->
<item name="popupTheme">@null</item>

第二个属性配置如下:

<style name="CustomerPopupMenuWindow">
	<!--这里的drawable,是一个圆角边框,蓝色填充-->				
  	<item name="android:background">@drawable/context_menu_style</item>
    <item name="android:textColor">@color/item_color_changed_by_mode</item>
</style>

配置之后,会发现二级菜单出现了嵌套,最外层是白色的window,内部是蓝色圆角边框的二级菜单。说明这个和alertdialog一样是在window类上有加了一个view的形式。可以参考我的alertdialog修改内容
链接

正确的翻代码

  1. 翻找ActionBar源码
    public abstract class ActionBar
    //是一个抽象类,找实现
    public class ToolbarActionBar extends ActionBar
    //这个是我们要找的toolbar类,这个其实就是我刚刚说的那个view
    public class WindowDecorActionBar extends ActionBar implements
        ActionBarOverlayLayout.ActionBarVisibilityCallback  
    //这一个其实我上面说的window
    
  2. 在ToolbarActionBar.class中,可以找到
    private DecorToolbar mDecorToolbar;
    //这哥也是抽象类,顺藤摸瓜,我们就找到了我们最后需要的
    public class ActionBarView extends AbsActionBarView implements DecorToolbar
    //在这个类里,我们可以找到ActionMenuPresenter.class,看这个类的名字,就知道这是用来干啥的。就不必再解释了吧。这个实际上是定义在AbsActionBarView的。
    
    之后,在这个ActionMenuPresenter.class中,我找到了这个代码
    private OverflowPopup mOverflowPopup;
    private class OverflowPopup extends MenuPopupHelper {
        public OverflowPopup(Context context, MenuBuilder menu, View anchorView,
                boolean overflowOnly) {
    		//注意这里com.android.internal.R.attr.actionOverflowMenuStyle,这个就是我们要找到二级菜单的样式属性
            super(context, menu, anchorView, overflowOnly,
                    com.android.internal.R.attr.actionOverflowMenuStyle);
            setGravity(Gravity.END);
            setPresenterCallback(mPopupPresenterCallback);
        }
    
        @Override
        protected void onDismiss() {
            if (mMenu != null) {
                mMenu.close();
            }
            mOverflowPopup = null;
    
            super.onDismiss();
        }
    }
    
    com.android.internal.R.attr.actionOverflowMenuStyle这个就是我们要找的,之后我们themes文件找这个,会发现
    <item name="actionOverflowMenuStyle">@style/Widget.Material.Light.PopupMenu.Overflow</item>
    <!--styles_material.xml-->
    <style name="Widget.Material.Light.PopupMenu.Overflow" parent="Widget.Material.PopupMenu.Overflow"/>
    <!--注意对应关系和继承关系就可以看明白了-->
    <style name="Widget.Material.ListPopupWindow">
        <item name="dropDownSelector">?attr/listChoiceBackgroundIndicator</item>
        <item name="popupBackground">@drawable/popup_background_material</item>
        <item name="popupElevation">@dimen/floating_window_z</item>
        <item name="popupAnimationStyle">@empty</item>
        <item name="popupEnterTransition">@transition/popup_window_enter</item>
        <item name="popupExitTransition">@transition/popup_window_exit</item>
        <item name="dropDownVerticalOffset">0dip</item>
        <item name="dropDownHorizontalOffset">0dip</item>
        <item name="dropDownWidth">wrap_content</item>
    </style>
    
    <style name="Widget.Material.PopupMenu" parent="Widget.Material.ListPopupWindow"/>
    
    <style name="Widget.Material.PopupMenu.Overflow">
        <item name="overlapAnchor">true</item>
        <item name="dropDownHorizontalOffset">-4dip</item>
    </style>
    

最后,在自己的style文件中,配置actionOverflowMenuStyle这个属性就可以了。

总结

整个过程,还是比较曲折的。我也是试了几种思路才改出来了的。希望大家提出修改意见。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值