Android 主题

Theme、Style、Attr的基本概念
Attr:属性,风格样式的最小单元;

Style:风格,它是一系列Attr的集合用以定义一个View的样式,比如height、width、padding等;

Theme:主题,它与Style作用一样,不同于Style作用于个一个单独View,而它是作用于Activity上或是整个应用,并具有向下的覆盖特性

Theme的定义
Theme的定义基本是一致的,主要是外部由一个一对style标签,内部通过item指明所定义的各个属性,下面的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/colorAccent</item>
    </style>

Theme的继承
1)通过parent属性进行系统主题的继承

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

2)通过“.”进行自定义主题的继承

    <style name="AppTheme.NoActionbar">
    <item name="windowActionBar">false</item>
    <item name="windowNoTitle">true</item>
    </style>

“.”前面是我们自定义的主题name,后面那就随意了,怎么写都可以了

style的继承与Theme一致,如果你原来不明白别人为何这样写,那么现在你肯定是知道了

Theme和Style的区别
定义上的区别:无太大区别,主要是属性不同,写法上基本一致
使用上的区别: 
对于单个控件通过style进行引入(此时style不会向下覆盖); 
对于Activity、Application等窗口级向下应用的通过theme进行引入;
使用系统预置的style
<!-- 使用系统预制style -->
<activity android:theme="@android:style/Theme.Dialog">

<!-- 使用系统预制但局部修改的style -->
<activity android:theme="@style/CustomTheme">

<color name="custom_theme_color">#b0b0ff</color>

<style name="CustomTheme" parent="android:Theme.Light">
    <item name="android:windowBackground">@color/custom_theme_color</item>
    <item name="android:colorBackground">@color/custom_theme_color</item>
</style>
使用Android系统内置的style,请务必加上“android:”

ThemeOverlays
在所有可用的主题中,我们可以发现一个名字带有 ThemeOverlay 的系列: 
ThemeOverlay 
ThemeOverlay.Light 
ThemeOverlay.ActionBar.Light 
ThemeOverlay.ActionBar.Dark 
这些主题又是做什么的呢?答案是 仅用于为特定的用途定义必要的属性。

如果你不清楚,请看测试

我们首先创建两个toolbar的style

    <style name="AppTheme.AppBar1" parent="ThemeOverlay.AppCompat.Light"/>
    <style name="AppTheme.AppBar2" parent="ThemeOverlay.AppCompat.Dark"/>

添加toolbar进行测试

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        app:theme="@style/AppTheme.AppBar1"
        android:background="@color/colorPrimary"/>


修改为第二个

通过改变主题我们可以很轻松的实现界面的View的样式变换,是不是会很方便。

Theme的选用
其是很简单,在MD设计(也就是5.0)被推出之后,google推出了几个material的主题,但你不必去使用这些主题,因为有更好的替代方案 
Theme.AppCompat 
Theme.AppCompat.Light, 
Theme.AppCompat.NoActionBar等等 
这些主题既保证了向下的兼容又兼顾了material的主题设计,并与materiial的各个主题一一对应,你在选择的时候使用以Theme.AppCompat开头的主题准是没错。

Attr
首先以layout_width为例分析自定义属性

<declare-styleable name="ViewGroup_Layout">
    <attr name="layout_width" format="dimension">
        <enum name="fill_parent" value="-1" />
        <enum name="match_parent" value="-1" />
        <enum name="wrap_content" value="-2" />
    </attr>
</declare-styleable>

declare-styleable代表自定属性组,attr则是代表属性,name是属性的标识,format是该属性的值类型,内部为enum表示值是唯一的,只可选其一。

再来看一下text的style

<attr name="textStyle">
    <flag name="normal" value="0" />
    <flag name="bold" value="1" />
    <flag name="italic" value="2" />
</attr>

此时attr的内部是flag,代指属性值是可叠加使用的,比如textStyle = bold|italic则是加粗和斜体的叠加。

format属性的可选值如下 
 
其中,reference代表引用,我们常用的@drawable/myImage、@color/myColor等都是这么干的。

ok,attr内部也只有enum和flag两种类型的属性,看完这个相信你可以自行定义属性了。

特别注意,当你的format选择错误的时候,填入对应的值AS并不会报错,所以具体实践时请留心

Attr的获得方法
有些情况下,我们可能需要使用theme中的属性值,比如下面我们想让一个TextView直接显示dogName这个属性的内容,并且使用系统字体的颜色,则可以如下做:

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:textColor="?android:textColorSecondary"
    android:text="?attr/dogName"/>

获得一个Attr的方法,不同于普通资源使用@符号获得的方式,而是需要使用?符号来获得属性,整体的表达方式如下:

?[:][/] 
如果是本应用中的attr使用,则可以省去<package_name>部分。

此处的textColor使用当前主题的android:textColorSecondary属性内容。因为资源工具知道此处是一个属性,所以省去了attr (完整写法:?android:attr/textColorSecondary)。

Attr的使用优先级:View的Style>Activity的Theme>Application的Theme,所以说你可以定义整个应用的总体风格,但局部风格你也可以做出自己的调整。
 

2,Holo主题:Android3.0 (API11)开始,Google推出了Holo主题(就是我们印象中的黑底白字蓝主色的主题)。在4.0重google又发布了应用设计规范Android Design。有了设计规范的指导,就有了更多的应用采用Holo主题。所以我们可以简单认为Android Design就是Holo主题。但是这种主题是适合移动设备,其他平台略显突兀。

      在4.0之前Android可以说是没有设计可言的,在4.0之后推出了Android Design,从此Android在设计上有了很大的改善,而在程序实现上相应的就是Holo风格,所以你看到有类似 Theme.Holo.Light、 Theme.Holo.Light.DarkActionBar 就是4.0的设计风格,但是为了让4.0之前的版本也能有这种风格怎么办呢?这个时候就不得不引用v7包了,所以对应的就有 Theme.AppCompat.Light、Theme.AppCompat.Light.DarkActionBar,如果你的程序最小支持的版本是API14(即Android 4.0),那么可以不用考虑v7的兼容。

3,Material 主题:从Android5.0(API21)开始,Google又推出了材料设计语言Material Design,又叫Google Design。MD崇尚的就是图层扁平化,所有图层像纸或者卡片一样重叠在一起,所以Android5.0就有了RecyclerView和CardView。图层之间有间隔,所以Android5.0中有了translation和elevation两个属性。同时也规范了Android的运动元素,界面上的每个元素不是无故产生的,同时每个图层的产生和消失都有方向的约定,从哪里来就往哪里去,这也是为什么Android 5.0中会有Ripple,Circular Receal,Activity Transition.

     Android在5.0版本推出了Material Design的概念,这是Android设计上又一大突破。对应的程序实现上就有Theme.Material.Light、 Theme.Material.Light.DarkActionBar等,但是这种风格只能应用在在5.0版本的手机,如果在5.0之前应用Material Design该怎么办呢?同样的引用appcompat-v7包,这个时候的Theme.AppCompat.Light、Theme.AppCompat.Light.DarkActionBar就是相对应兼容的Material Design的Theme。

二,Android Theme的分类

    1,android:Theme                             API 1 开始
    2,android:Theme.Holo                     API 11(android3.0) 开始
    3,android:Theme.DeviceDefault      API 14(android4.0) 开始
    4,android:Theme.Material               API 21(android5.0) 开始
    5,Theme.AppCompat                      兼容包AppCompat_v7中的主题


API 1:
android:Theme 根主题
android:Theme.Black 背景黑色
android:Theme.Light 背景白色
android:Theme.Wallpaper 以桌面墙纸为背景
android:Theme.Translucent 透明背景
android:Theme.Panel 平板风格
android:Theme.Dialog 对话框风格
 
API 11:
android:Theme.Holo Holo根主题
android:Theme.Holo.Black Holo黑主题
android:Theme.Holo.Light Holo白主题
 
API 14:
Theme.DeviceDefault 设备默认根主题
Theme.DeviceDefault.Black 设备默认黑主题
Theme.DeviceDefault.Light 设备默认白主题
 
API 21: (网上常说的 Android Material Design 就是要用这种主题)
Theme.Material Material根主题
Theme.Material.Light Material白主题
 
兼容包v7中带的主题:
Theme.AppCompat 兼容主题的根主题
Theme.AppCompat.Black 兼容主题的黑色主题
Theme.AppCompat.Light 兼容主题的白色主题


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


Android5.0设置主题样式:


<style name="RedTheme" parent="android:Theme.Material">
        <!-- 状态栏颜色,会被statusBarColor效果覆盖-->
        <item name="android:colorPrimaryDark">@color/status_red</item>
        <!-- 状态栏颜色,继承自colorPrimaryDark -->
        <item name="android:statusBarColor">@color/status_red</item>
        <!-- actionBar颜色 -->
        <item name="android:colorPrimary">@color/action_red</item>
        <!-- 背景颜色 -->
        <item name="android:windowBackground">@color/window_bg_red</item>
        <!-- 底部栏颜色 -->
        <item name="android:navigationBarColor">@color/navigation_red</item>
        <!-- ListView的分割线颜色,switch滑动区域色-->
        <item name="android:colorForeground">@color/fg_red</item>
        <!-- popMenu的背景色 -->
        <item name="android:colorBackground">@color/bg_red</item>
        <!-- 控件默认颜色 ,效果会被colorControlActivated取代  -->
        <item name="android:colorAccent">@color/control_activated_red</item>
        <!-- 控件默认时颜色  -->
        <item name="android:colorControlNormal">@color/control_normal_red</item>
        <!-- 控件按压时颜色,会影响水波纹效果,继承自colorAccent  -->
        <item name="android:colorControlHighlight">@color/control_highlight_red</item>
        <!-- 控件选中时颜色 -->
        <item name="android:colorControlActivated">@color/control_activated_red</item>
        <!-- Button的默认背景 -->
        <item name="android:colorButtonNormal">@color/button_normal_red</item>
        <!-- Button,textView的文字颜色  -->
        <item name="android:textColor">@color/white_text</item>
        <!-- RadioButton checkbox等控件的文字 -->
        <item name="android:textColorPrimaryDisableOnly">@color/white_text</item>
        <!-- actionBar的标题文字颜色 -->
        <item name="android:textColorPrimary">@color/white_text</item>

为什么需要Theme.AppCompat主题
android:Theme
android:Theme.Holo
android:Theme.Material
这三个主题就对应了上一节说的三种Android主题。android:Theme是所有主题的超级父类。所有的主题都是它继承或者间接继承来的。android:Theme.Holo从Api 11开始才可以使用。android:Theme.Material从Api 21开始可以使用

如果我们要在不同版本的系统上用各自的主题,比如在4.0之下的系统用android:Theme,4.0至5.0的系统用Holo主题,5.0及之后的系统使用Material Design,那我们需要建不同的value-vX目录。在各自的目录中的style继承相应的系统主题。在运行是系统就会根据平台版本使用相应的主题。如果使用的主题没有找到,那么系统就会根据App指定的targetSdkVersion自动设置主题,假如设置的targetSdkVersion超过了系统的版本,系统就设置为支持的最高系统sdk版本的主题

如果我要在Android 4.4(支持Holo主题)的机器上使用Material主题(Android 5.0)怎么办呢?(就是低版本要使用高版本的系统主题)没事,Google已经帮我们想好了解决方案。毕竟Google希望在不同的平台和版本上推广Material Design嘛。这样才能给用户提供一致性的体验。介于此,Android里就有了Theme.AppCompat主题和AppCompatActivity。细心的同学也会发现现在用Android Studio新建一个工程,默认的MainActivity继承的是AppCompatActivitiy,默认的主题就是Theme.AppCompat

Theme.AppCompat,这个主题可以让5.0以下的系统使用Material主题。我们只需要让我们的系统主题继承Theme.AppCompat即可

使用了Theme.AppCompat之后,targetSdkVersion就不受影响了。应用使用了Theme.AppCompat主题,不论我们的targetSdkVersion指定为多少,跑在任意版本的系统上都会呈现出Material主题
 

 

Android 的默认字体

Android 系统默认使用的是一款叫做 Robote 的字体。Robote 本身就是 Google 自己的字体格式,Android 和 Chrome 操作系统上,默认都会使用 Robote 字体,并且也是 Google 视觉语言推荐的字体。

想要了解更多关于 Robote 的内容,可以去 Google 的网站上查看。

https://fonts.google.com/specimen/Roboto

正常来说,Robote 就已经提供了多种的选择,例如:粗细、斜体 等等。但是通常它并不能满足我们设计师的需要。

接下来看看当我们想要使用 Android 内置的一些字体的时候,我们需要使用哪些属性。

三、哪些属性可以影响字体

Android 本身已经提供了一些修改字体样式的属性和方法。

当你想要修改字体的时候,你将面对三个属性,它们都有对应的 Java 方法。

  • android:textStyle
  • android:typeface
  • android:fontFamily

下面来分别详细的说明这几个属性。

3.1 android:textStyle

textStyle 主要用于设定一些字体的样式,它是对所有的字体都生效的。也就是说哪怕你替换了字体,依然可以使用 textStyle 来修饰它的样式。textStyle 本身支持的可选项有 normal|bold|italic,它们也非常的好理解,就是普通|粗体|斜体

Android 主题

可以看到,字体是不受 textStyle 影响的,这里影响的只有它的样式。

3.2 android:typeface

typeface 可以用于设置一些默认的字体,它可选的属性有 normal|sans|serif|monospace 等。normal 和 sans 的字体其实是一样的,serif 是一个带衬线的字体,而 nonospace 是等宽字体。

光这样说,其实也无法理解它们,直接上效果图比较能说明问题。

Android 主题

可以看到 serif 在默认的字体上,增加了衬线。而 nonospace 限制了每个字符的宽度,让它们达到一个等宽的效果。

等宽其实很好理解,衬线到底是什么意思?这里引用*的一张图,就能很直观的说明问题。

Android 主题

衬线其实就是字体边缘的那一点点小啾啾。

3.3 android:fontFamily

fontFamily 看着像是对 typeface 的一次加强,从它的可选项就能看出来,它更细致的区分了字体的样式。

fontFamily 的可选项还是很多的,这里就不一一列举了。不过需要注意,有一些字体的设置是有版本限制的。

例如:sans-serif-medium 是需要 Android 5.0 的版本才支持的。

下面直接举几个例子看看效果了:

Android 主题

需要注意的是,如果同时配置了 typeface 和 fontFamily ,将使用 fontFamily 配置的字体。

而除了 typeface 和 fontFamily 会有冲突之外,它们俩都是可以配合 typeStyle 属性一起使用的,也就是说,这里配置的字体,都是可以再加粗或者加斜体。

四、利用主题修改全局字体

如果你能说服你的设计师,接受系统字体的话,你可以在 Theme 中,去配置你需要的默认字体。

在 application 中,通过 android:theme 来配置一个 App 的主题。一般新创建的项目,都是 @style/AppTheme 。在其中追加关于字体的属性 android:fontFamily,它就可以完成对全局设置一个系统字体。当然你可以对一个单独的 TextView 配置一个特别的字体,都是可以接受的。

Android 主题

五、使用自定义字体

有时候,Android 系统默认的字体已经无法满足我们的需求了,这个时候我们就会需要使用一些定制的特殊字体。

关于字体,这里推荐两个网站,可以下载到免费的字体供我们使用。

https://fonts.google.com/

https://www.1001freefonts.com/

字体文件,通常都是设计师提供给我们的,一般都是 .ttf(TrueType) 或者 .otf(OpenType) 这两种格式的,比较常用的是 .ttf 格式的。

通常我们会把字体文件放再 assets 目录下,想要加载字体文件,需要使用到 Typeface 这个类,它其中提供了一些 Api ,用于帮助我们来加载一个我们自定义的字体文件。

例如下面的例子,是一个通用的做法。

Android 主题

而 Typeface 并不只是为了加载一些自定义的字体文件,系统内置的字体,也是通过 Typeface 来管理的,可以说它就是 Android 的字体大管家。

 

https://blog.****.net/yanbober/article/details/45970721

https://blog.****.net/yanbober/article/details/51015630

https://www.jianshu.com/p/dd79220b47dd