美文网首页Android经验和架构AndroidAndroidk开发合集
通过源码分析,修改AlertDialog按钮的颜色

通过源码分析,修改AlertDialog按钮的颜色

作者: 于连林520wcf | 来源:发表于2016-04-13 16:35 被阅读15097次
    对话框

    弹出对话框对任何一个Android开发者都不是什么难事,代码也非常简单,简单的贴出来都觉得是个不光彩的事。

        public void showDialog(View v){
            AlertDialog.Builder builder=new AlertDialog.Builder(this);
            builder.setTitle("dialog");
            builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    // .....
                }
            });
            builder.setNegativeButton("取消",null);
            builder.show();
        }
    

    如果这是一个普通的AlertDialog教程,写到此处就大功告成了。问题是,公司产品经理感觉Dialog按钮的颜色不舒服,和绿帽子一样颜色,太不爽,想改成和顶部AppBar一个颜色。
    我想了想,觉得因为一个Dialog跳槽走人也说不过去,只能拍拍胸脯说没问题。

    众所周知,我们可以setView()定制不同界面样式的Dialog,随便你在布局中发挥

            AlertDialog.Builder builder=new AlertDialog.Builder(this);
            builder.setView(view);
            builder.show();
    

    但是这种方法还要去搭建一个布局文件,太不爽。
    紧接着我突然想到了,通过修改Dialog主题样式从而改变Dialog按钮的颜色。天才啊~
    直接打开主题样式文件 values\styles.xml。

    <resources>
    
        <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
            <item name="colorPrimary">@color/colorPrimary</item>
            <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
            <item name="colorAccent">@color/colorAccent</item>
        </style>
    
    </resources>
    
    

    当前程序采用的是AppCompat的主题,也是目前程序主流的主题。
    然,并,卵!
    如何修改Dialog样式了呢。上面的colorPrimary,colorAccent等分别控制什么的颜色呢。别着急,先看下面一张图:

    主题颜色
    1. android:colorPrimaryDark 应用的主要暗色调,statusBarColor默认使用该颜色
    2. android:statusBarColor 状态栏颜色,默认使用colorPrimaryDark
    3. android:colorPrimary 应用的主要色调,actionBar默认使用该颜色
    4. android:windowBackground 窗口背景颜色
    5. android:navigationBarColor 底部栏颜色
    6. android:colorForeground 应用的前景色,ListView的分割线,switch滑动区默认使用该颜色
    7. android:colorBackground 应用的背景色,popMenu的背景默认使用该颜色
    8. android:colorAccent 一般控件的选种效果默认采用该颜色
    9. android:colorControlNormal 控件的默认色调
    10. android:colorControlHighlight 控件按压时的色调
    11. android:colorControlActivated 控件选中时的颜色,默认使用colorAccent
    12. android:colorButtonNormal 默认按钮的背景颜色
    13. android:textColor Button,textView的文字颜色
    14. android:textColorPrimaryDisableOnly RadioButton checkbox等控件的文字
    15. android:textColorPrimary 应用的主要文字颜色,actionBar的标题文字默认使用该颜色

    上面加粗的就是创建项目默认带的,哇~ 原来主题可以控制这么多颜色啊。其实这还不是全部的啊。
    问题回到主题,如何修改AlertDialog按钮的颜色啊。上面没有写着啊。不要怕,咱们去看看AlertDialog的源码。
    AlertDialog是通过Builder创建的。

            public Builder(Context context) {
                this(context, resolveDialogTheme(context, 0));
            }
    
    

    可以看到片Build创建的时候调用了resolveDialogTheme这个方法,英语好的一眼就知道这是解析主题的意思,点进去看看这个方法:

        static int resolveDialogTheme(Context context, int resid) {
            if (resid >= 0x01000000) {   // start of real resource IDs.
                return resid;
            } else {
                TypedValue outValue = new TypedValue();
                context.getTheme().resolveAttribute(R.attr.alertDialogTheme, outValue, true);
                return outValue.resourceId;
            }
        }
    

    *** 核心是看这个:context.getTheme().resolveAttribute(R.attr.alertDialogTheme, outValue, true);***
    这个话的意思就是上下文获取当前主题解析alertDialogTheme这个属性。
    原来终于明白了,我们要想修改AlertDialog样式需要在主题中设置alertDialogTheme,这个属性。

        <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
            <!-- Customize your theme here. -->
            <item name="colorPrimary">@color/colorPrimary</item>
            <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
            <item name="colorAccent">@color/colorAccent</item>
            <item name="alertDialogTheme">怎么写啊??</item>
        </style>
    

    问题来了,alertDialogTheme这个又该怎么写呢。这次ctrl+左键点击Theme.AppCompat.Light.DarkActionBar进去看看默认的alertDialogTheme是怎么配置的,我们按照葫芦画瓢就可以了。
    进来千万不要头晕,我们来缕缕:
    首先

    <style name="Theme.AppCompat.Light.DarkActionBar" parent="Base.Theme.AppCompat.Light.DarkActionBar"/>
    

    继续翻家谱,点击父样式Base.Theme.AppCompat.Light.DarkActionBar

        <style name="Base.Theme.AppCompat.Light.DarkActionBar" parent="Base.Theme.AppCompat.Light">
            <item name="actionBarPopupTheme">@style/ThemeOverlay.AppCompat.Light</item>
            <item name="actionBarWidgetTheme">@null</item>
            <item name="actionBarTheme">@style/ThemeOverlay.AppCompat.Dark.ActionBar</item>
    
            <!-- Panel attributes -->
            <item name="listChoiceBackgroundIndicator">@drawable/abc_list_selector_holo_dark</item>
    
            <item name="colorPrimaryDark">@color/primary_dark_material_dark</item>
            <item name="colorPrimary">@color/primary_material_dark</item>
        </style>
    

    发现Base.Theme.AppCompat.Light.DarkActionBar还是没有我们想要的,继续点击Base.Theme.AppCompat.Light,继续往上翻

    <style name="Base.Theme.AppCompat.Light" parent="Base.V7.Theme.AppCompat.Light"></style>
    

    继续...

    <style name="Base.V7.Theme.AppCompat.Light" parent="Platform.AppCompat.Light">
        ....
       <item name="alertDialogTheme">@style/Theme.AppCompat.Light.Dialog.Alert</item>
    </style>
    

    终于功夫不负有心人,找到了alertDialogTheme这个属性,看看它对应的是@style/Theme.AppCompat.Light.Dialog.Alert
    我们把这个代码复制到我们的样式中,这就相当于你什么都没改:

        <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
            <item name="colorPrimary">@color/colorPrimary</item>
            <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
            <item name="colorAccent">@color/colorAccent</item>
            <item name="alertDialogTheme">@style/Theme.AppCompat.Light.Dialog.Alert</item>
        </style>
    

    于是乎我们开始自定义这个样式Theme.AppCompat.Light.Dialog.Alert

        <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
            <item name="colorPrimary">@color/colorPrimary</item>
            <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
            <item name="colorAccent">@color/colorAccent</item>
            <item name="alertDialogTheme">@style/Theme.AppCompat.Light.Dialog.Alert.Self</item>
        </style>
    
        <style name="Theme.AppCompat.Light.Dialog.Alert.Self"
               parent="@style/Theme.AppCompat.Light.Dialog.Alert">
              <!--怎么写呢?-->
        </style>
    

    怎么自定义呢,于是乎,又需要翻看Theme.AppCompat.Light.Dialog.Alert的源码了。过程和上面雷同,需要多翻几次,就不列举了。直接说结果,最终你会发现
    Theme.AppCompat.Light.Dialog.Alert继承自Base.V7.Theme.AppCompat.Light

    <style name="Base.V7.Theme.AppCompat.Light" parent="Platform.AppCompat.Light">
        ....
      
    </style>
    

    这个是不是很眼熟啊,没错,上面的代码曾经翻到过它。这时候如果你按照正常思维模式去查看哪个属性控制按钮颜色,你还需要翻看AlerDialog源码,我只能说有点麻烦了,很不爽的。
    那怎么看呢?
    介绍一个小技巧。
    我们先看按钮默认的颜色。

    按钮颜色

    然后看Base.V7.Theme.AppCompat.Light样式下只有colorAccent 对应这个颜色。

    按钮颜色
    于是乎我们可以猜测,colorAccent 这个属性可能是控制按钮的颜色。于是乎赶快添加到自定义的样式中。填写和状态栏的一样的颜色:
        <style name="Theme.AppCompat.Light.Dialog.Alert.Self"
               parent="@style/Theme.AppCompat.Light.Dialog.Alert">
            <item name="colorAccent">#3F51B5</item>
        </style>
    

    运行看看效果吧:

    Paste_Image.png

    哇~ 终于改成和状态栏一个颜色了。
    把最终代码粘贴出来,仅仅是改了values/styles中的主题样式:

        <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
            <!-- Customize your theme here. -->
            <item name="colorPrimary">@color/colorPrimary</item>
            <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
            <item name="colorAccent">@color/colorAccent</item>
            <!--自定义AlertDialog-->
            <item name="alertDialogTheme">@style/Theme.AppCompat.Light.Dialog.Alert.Self</item>
        </style>
        <style name="Theme.AppCompat.Light.Dialog.Alert.Self"
               parent="@style/Theme.AppCompat.Light.Dialog.Alert">
            <!--修改AlertDialog按钮的颜色-->
            <item name="colorAccent">#3F51B5</item>
        </style>
    </resources>
    

    虽然,过程很复杂,但是结果确很简单。开发是非常重视结果的,但学习的时候过程的体验还是必不可少的,通过学习这个分析过程,大家可以尝试修改其它控件默认的样式啦。
    更多精彩请关注微信公众账号likeDev,公众账号名称:爱上Android。

    likeDev.jpg

    相关文章

      网友评论

      • 曾经的你呀:两个Button 的颜色要不一样怎么用 Theme 简洁高效处理
      • noahzhy:我一般这样写,防止有的时候PM要确定和取消按钮不一样颜色
        dialog.getButton(AlertDialog.BUTTON_NEGATIVE).setTextColor(getColor(R.color.colorPrimary))
        dialog.getButton(AlertDialog.BUTTON_POSITIVE).setTextColor(getColor(R.color.colorPrimary))
        曾经的你呀:我也是这样写,但是要多些好多代码。有没有更简单的
      • Zurich37度:<item name="alertDialogTheme">@style/Theme.AppCompat.Light.Dialog.Alert.Self</item>
        这里的引用需要加上"android:",不然不起作用
        <item name="android:alertDialogTheme">@style/Theme.AppCompat.Light.Dialog.Alert.Self</item>
      • captain991:答主分析的思路挺好的,只是我有一点问题,我用的也是support v7包下的AlertDialog,默认AlertDialog的按钮颜色就是跟随主题的colorAccent的。另外,我这里Base.V7.Theme.AppCompat.Light中的alertDialogTheme指定的是@style/ThemeOverlay.AppCompat.Dialog.Alert,再追进去只有这两个属性
        <item name="android:windowMinWidthMajor">@dimen/abc_dialog_min_width_major</item>
        <item name="android:windowMinWidthMinor">@dimen/abc_dialog_min_width_minor</item>,
        所以我猜测他还是直接从AppTheme中取出colorAcdent作为按钮颜色的
        于连林520wcf: @captain991 估计版本不一样
        captain991:@于连林520wcf 我有点不是很明白你的意思,咱们用的不是都是v7包下的AlertDialog么,怎么好像还不太一样
        于连林520wcf: @captain991 嗯,你这没错,我用的确实是V7包的dialog
      • BennyYen:真心不错呀
        谢谢老师!
        :kissing_heart:
      • cfe1c1fef66e:感谢分享 :stuck_out_tongue_winking_eye:
      • Will_1993:直接通过Html来加载就好,省时省力,并且不存在适配问题
        alertDialog = new AlertDialog.Builder(this)
        .setTitle(ResourceUtil.getStringResource(R.string.cache_limit)).setView(layout)
        .setNegativeButton(Html.fromHtml("<font color='#fd3535'>" +
        ResourceUtil.getStringResource(R.string.cancle) + "</font>"),
        new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialogInterface, int i) {

        }
        }).create();
        Mid_Night:这个我试了没效果,不管是app下的还是v7下的,都不变颜色
      • 峰子邹:我用了V7包下的AlertDialog,但是没有起作用,很奇怪。
        5997854c43de:表示一样,只能通过new AlertDialog.Builder(this, R.style.AlertDialogTheme)的方式。你解决了吗?
      • BigLong:<item name="colorAccent">the color you want</item>

        可以直接添加这个选项实现,运行在android 6.0 以上时。 :joy:
        Will_1993:直接通过Html来加载就好,省时省力。
        alertDialog = new AlertDialog.Builder(this)
        .setTitle(ResourceUtil.getStringResource(R.string.cache_limit)).setView(layout)
        .setNegativeButton(Html.fromHtml("<font color='#fd3535'>" +
        ResourceUtil.getStringResource(R.string.cancle) + "</font>"),
        new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialogInterface, int i) {

        }
        }).create();
        BigLong:@于连林520wcf 对的
        于连林520wcf:@BigLong 你可能用的不是 support v7 下的dialog 你这个不兼容低版本
      • 113bdaafbb89:太赞了 :pray:
      • Maxoxo:感谢楼主,讲解得很详细,过程+结果都有,大赞 :stuck_out_tongue_winking_eye:
      • wo叫天然呆:为什么我修改后无效?我values/19/21下的styles都添加了,还是没变化
        wo叫天然呆:@于连林520wcf 好的,我试试v7下的dialog
        于连林520wcf: @wo叫天然呆 修改默认dialog颜色直接改colorAcent就行
        于连林520wcf: @wo叫天然呆 我是用的supportv7下的dialog
      • Andy周:受益了
      • 7e7435383186:这样是可以的,但是在4.0的系统以下,我用了new AlertDialog.Builder(this,R.style.MyAlertDialogStyle),这样的形式才成功
        5997854c43de:@于连林520wcf 使用V7包下的AlertDialog, 还是识别不了自定义的style。
        ```

        <item name="android:alertDialogTheme">@style/AlertDialogTheme</item>

        <style name="AlertDialogTheme" parent="Theme.AppCompat.Light.Dialog.Alert">
        <!-- Used for the title and text -->
        <item name="android:textColorPrimary">#000000</item>
        <!-- Used for the buttons -->
        <item name="colorAccent">#000000</item>
        </style>
        ```
        7e7435383186:谢谢 于帅
        于连林520wcf:@胡大象 用v7包下的不用这么麻烦
      • 7e7435383186:写的好好,但是我遇到了下面的问题:
        我用了V7包的AlertDialog, 建立出了的AlertDialog的Button的颜色属性没有变化,我继承的Activity是AppCompatActivity。但是当我不用V7包的时候 ,dialogButton里面的颜色属性就变化的。
        于哥知道这是怎么回事吗?
        橘子周二:@胡大象 AppCompatActivity就是为了方便你使用MaterialDesign的风格,里面采用的都是appcompat-v7下的资源。
        橘子周二:反了吧,继承AppCompatActivity时 需要指定V7包 设置 colorAccent才有用
        于连林520wcf:@胡大象 不用v7包下的直接修改colorAccent就可以了
      • 夏广成:还能继续从于老师这取经,真幸福:smile::smile:
        于连林520wcf: @snowfly 哈哈
      • 谭冉冉:dialog.getButton(dialog.BUTTON_NEGATIVE).setTextColor(neededColor); dialog.getButton(dialog.BUTTON_POSITIVE).setTextColor(neededColor);

        这个也可以做到
        谭冉冉:@于连林520wcf 这个可以直接获取到它的button,然后就当普通的button用,字体大小颜色样式背景都可以啦。
        于连林520wcf: @谭冉冉 多谢!之前没发现这个方法,多谢
        谭冉冉:@谭冉冉 需要在dialog show或者create 之后才可以更改
      • 徐晓光_891015:真心不错
        于连林520wcf:@徐晓光_891015 谢谢 赞赏
      • 李斯维:其实你的产屏经理还算是不错的,我用这个对话框的时候,我这边leader就说:"你这不靠谱啊,你看,别人家的确定和取消都不是一个颜色,你这是原生的?“然后就打开一个网页说要这样的要这样的要这样的。
        曾经的你呀:我们的产品和设计把确定和取消改成了一红一绿。。。。
        于连林520wcf:@545a3c856c5f 这年头都不容易
      • 0b70442a237e:恩 自定义主题确实能减少好多工作
      • 6e1fe334b05e:恩 省不少事啊
      • MycroftWong:很好,弄明白android的style/theme其实减少很多不必要的工作
      • b09f682c4d8b:自定义是不是很容易呢?
        于连林520wcf: @中山狼就是我 不是很难

      本文标题:通过源码分析,修改AlertDialog按钮的颜色

      本文链接:https://www.haomeiwen.com/subject/unnwlttx.html