美文网首页Android新优化
安卓统一样式和主题的一些细节知识点

安卓统一样式和主题的一些细节知识点

作者: 奋斗小青年Jerome | 来源:发表于2017-09-22 13:57 被阅读202次
    • 使用Theme来统一基础背景色
    <!-- Base application theme. -->
        <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/colorNormalText</item>
            <item name="windowBackground">@color/windowBackgroundColor</item>
            <item name="textColorPrimary">@color/colorNormalText</item>
        </style>
    

    Theme里面统一设置了默认的背景颜色和字体颜色,在xml布局过程中,不单独对控件设置颜色,则使用默认
    Theme的各种参数的解释

    theme.png
    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的标题文字默认使用该颜色
    • 使用Style来统一常用的基础样式
      常用的基础控件(Button,EditTextView)等可以抽取到Style,使用时引用即可,这样要改的时候直接改一个地方即可
    • ToolBar不一定好用
      官方的toolBar在某些情况下不一定好用,比如Title文字不能居中;不能添加左边的menu,左侧的返回按钮navigationIcon不能设置大小和padding值;menu在长按之后会弹出吐司,即使menu的title设置为空字符串,当然这些问题也可以有很多方法弥补,在你确定一定要用toolBar的情况下;否则按照自定义一个跟toolbar高度一样的view的方式来作为toolBar是比较好的选择
    • 设置状态栏的颜色和状态栏字体颜色
      1.安卓4.4以上版本才开始支持修改状态栏颜色
      2.小米的MIUI,魅族的Flyme以及安卓6.0以上版本支持更改状态栏字体颜色,其他版本国内的rom目前没有找到好的解决办法
    //小米
      if (window != null) {
                Class clazz = window.getClass();
                try {
                    int darkModeFlag = 0;
                    Class layoutParams = Class.forName("android.view.MiuiWindowManager$LayoutParams");
                    Field field = layoutParams.getField("EXTRA_FLAG_STATUS_BAR_DARK_MODE");
                    darkModeFlag = field.getInt(layoutParams);
                    Method extraFlagField = clazz.getMethod("setExtraFlags", int.class, int.class);
                    if (dark) {
                        extraFlagField.invoke(window, darkModeFlag, darkModeFlag);//状态栏透明且黑色字体
                    } else {
                        extraFlagField.invoke(window, 0, darkModeFlag);//清除黑色字体
                    }
                
                } catch (Exception e) {
    
                }
    
    //魅族
     try {
                    WindowManager.LayoutParams lp = window.getAttributes();
                    Field darkFlag = WindowManager.LayoutParams.class
                            .getDeclaredField("MEIZU_FLAG_DARK_STATUS_BAR_ICON");
                    Field meizuFlags = WindowManager.LayoutParams.class
                            .getDeclaredField("meizuFlags");
                    darkFlag.setAccessible(true);
                    meizuFlags.setAccessible(true);
                    int bit = darkFlag.getInt(null);
                    int value = meizuFlags.getInt(lp);
                    if (dark) {
                        value |= bit;
                    } else {
                        value &= ~bit;
                    }
                    meizuFlags.setInt(lp, value);
                    window.setAttributes(lp);
                    result = true;
                } catch (Exception e) {
    
                }
    
    //android6.0以上版本
    getWindow().getDecorView().setSystemUiVisibility( View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
    

    注意6.0以上版本这里有坑,View的几个状态
    1.View.SYSTEM_UI_FLAG_VISIBLE:显示状态栏,
    Activity不全屏显示(恢复到有状态的正常情况)。
    2.View.INVISIBLE:隐藏状态栏,同时Activity会伸展全屏显示。
    3.View.SYSTEM_UI_FLAG_FULLSCREEN:Activity全屏显示,且状态栏被隐藏覆盖掉。
    4.View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN:Activity全屏显示,但状态栏不会被隐藏覆盖,状态栏依然可见,Activity顶端布局部分会被状态遮住。
    5.View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION:效果同 View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
    6.View.SYSTEM_UI_LAYOUT_FLAGS:效果同View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
    7.View.SYSTEM_UI_FLAG_HIDE_NAVIGATION:隐藏虚拟按键(导航栏)。有些手机会用虚拟按键来代替物理按键。
    8.View.SYSTEM_UI_FLAG_LOW_PROFILE:状态栏显示处于低能显示状态(low profile模式),状态栏上一些图标显示会被隐藏。

    • 使用着色器实现Drawable的tint功能
      Drawable的setColorFilter滤镜功能能够实现针对drawable的单独着色,例如app的一些icon,在某些情况下需要改变icon的颜色,一般我们就放两张图片,那么使用着色器就只需要一张图片;还有就是某些图片icon的按钮的按压效果,当按下去之后需要设置透明通道,将之前的图片覆盖一下,也可以使用着色器实现
            drawable.setColorFilter(color, PorterDuff.Mode.SRC_ATOP);
            iv.setImageDrawable(drawable);
    

    这里有坑,在项目中使用时,发现同一个drawable下的图片,只要设置过一次颜色之后,其他图片都会成为这个颜色,再次设置无效,google了一番,发现是因为Android底层可能为了节约资源,将这个图片在内存中以共享的方式提供,加上这句代码,就可以实现图片在内存中是以copy形式存在(其实copy这个词也不确切,应该是重新引用了)

            drawable.mutate();
            drawable.setColorFilter(color, PorterDuff.Mode.SRC_ATOP);
            iv.setImageDrawable(drawable);
    
    • 使用系统自带的AlertDialog来实现弹窗
      Support V7包在22.1.0之前的任何一个版本,AlertDialog一直都是Android4.0风格,直到Support-V7:22.1.0,在这之前,如果我们的项目中要使用Material样式的Dialog,Android5.0以下的设备根本不支持
      但是,support-v7更新到22.1.0之后,我们就再也不需要使用上面的开源库来获得MaterialDiaolg了
      但是... 系统自带的dialog能够定义的东西非常少,至少在api上没用能够定义字体颜色,按钮字体颜色和大小等属性,导致我们不得不自定义或者用第三方的库,那么其实我们只需要小小的更改一下系统dialog的style,就能实现很多东西
      这里要感谢于神的这篇文章,通过查看分析源码,来自定义style
      我们通过AlertDialog的Builder,跟源码
       static int resolveDialogTheme(@NonNull Context context, @StyleRes 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;
            }
        }
    

    发现系统要求我们如果需要自定义dialog属性,需要在theme里面使用alertDialogTheme,那么怎么去写这个alertDialogTheme呢,来看看系统怎么写的,我们就怎么写,于是就按照如下的style来写,这里有个小坑就是,我们自定义完了按钮字体颜色,运行发现content的字体颜色也跟着变了,

     <!--更改的系统的dialog样式-->
        <style name="Theme.AppCompat.Light.Dialog.Alert.Custom" parent="@style/Theme.AppCompat.Light.Dialog.Alert">
            <item name="android:background">@color/dialog_bg_color</item>
            <!--取消按钮字体颜色-->
            <item name="buttonBarNegativeButtonStyle">@style/buttonBarNegative</item>
            <!--确认按钮字体颜色-->
            <item name="colorAccent">@color/colorAccent</item>
        </style>
    
        <style name="buttonBarNegative" parent="@style/Widget.AppCompat.Button.ButtonBar.AlertDialog">
            <item name="android:textColor">@color/title_color</item>
        </style>
    

    查看了一下,忘记加textColorPrimary这个属性
    最终如下:

     <!--更改的系统的dialog样式-->
        <style name="Theme.AppCompat.Light.Dialog.Alert.Custom" parent="@style/Theme.AppCompat.Light.Dialog.Alert">
            <item name="android:background">@color/dialog_bg_color</item>
            <!--字体统一颜色-->
            <item name="android:textColorPrimary">@color/title_color</item>
            <!--取消按钮字体颜色-->
            <item name="buttonBarNegativeButtonStyle">@style/buttonBarNegative</item>
            <!--确认按钮字体颜色-->
            <item name="colorAccent">@color/colorAccent</item>
        </style>
    
        <style name="buttonBarNegative" parent="@style/Widget.AppCompat.Button.ButtonBar.AlertDialog">
            <item name="android:textColor">@color/title_color</item>
        </style>
    
    image.png

    成功通过更改系统的style实现的MaterialDesign风格的弹窗

    相关文章

      网友评论

        本文标题:安卓统一样式和主题的一些细节知识点

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