Android 主题设计全解析

Posted 痕迹天涯119

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 主题设计全解析相关的知识,希望对你有一定的参考价值。

android主题设计!有点乱?

初学Android的时候对Android的主题设计都是处在一种模糊的认知状态,为啥呢?

自定义时候的attr,普通view的style属性,activity以及application的theme属性,theme与style定义的一致性以及theme的众多可选性,系统预置的style属性的继承与使用等等……

OK,先不管这些乱七八糟的,如果你对Android的主题设计依旧存在某些疑问,请看完这篇文章。

Theme、Style、Attr的基本概念

Attr:属性,风格样式的最小单元;

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

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


Theme

Theme的概念验证

好吧,为了清晰的验证上面的说法,我这里举个例子

新建一个moudle,在styles.xml中有如下内容

<resources>

    <!-- 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/colorAccent</item>
    </style>

</resources>

可以看到该style定义了该主题下共享的三个颜色属性,以及继承了一个父主题
那么来看一下该主题应用的代码

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

此时 ,这个默认主题应用在了Application下,我们启动模拟器观看主题效果

普普通通没啥特别的,我们为前面的主题添加两个属性

        <item name="windowActionBar">false</item>
        <item name="windowNoTitle">true</item>

重新启动模拟器,你看到了什么

Activity的ActionBar被隐藏了,
是的,正如我前面所说,Theme一般应用于Application和Activity层级,并会继续向下覆盖,这里我们虽然只是设置了Application的theme属性,其下的所有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开头的主题准是没错。

那就有人问了,为毛线这么干,其他乱七八糟的主题又是啥呢?

这里我强烈推荐你看一篇文章(译文):android-themes-an-in-depth-guide


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,所以说你可以定义整个应用的总体风格,但局部风格你也可以做出自己的调整。


最近做了下反思,与其制造网络垃圾不如不去写文章,所以准备大幅度降低写作速度并致力于提升文章的质量,未来计划在自己进步的同时分享进步的干货并不断去删除原文,以保证整个博客的文章质量和可用性。

如果你对本文有什么问题和看法请及时告知,送人玫瑰手有余香,谢谢支持。

参考文章:
Attr、Style和Theme详解
Android开发之Theme、Style探索及源码浅析
ThemeOverlay
Android Themes — An in-depth guide

以上是关于Android 主题设计全解析的主要内容,如果未能解决你的问题,请参考以下文章

《Android源代码设计模式解析与实战》读书笔记(十八)

(AS笔记)Android全透明沉浸式主题样式——代码篇

Xcode 和 Android Studio,Eclipse等安卓开发工具比怎么样

如何做好性能优化?字节大老历时3个月为你整理出这份Android性能优化实战全解析

Android 之 IPC 进程通信全解析

Android之怎样全屏显示