Android主题的进化过程

在Android 3.0之前,Android的界面不论从系统还是控件的主题都是按钮为白色,点击事件为黄色。现在看来确实挺简陋的是吧。

从Android 3.0(Api 11)开始,Google推出了Holo主题(对,就是我们印象里的黑底白字蓝主色的那个主题),在4.0中更是发布了应用设计规范Android Design。有了设计规范的指导,便有了更多的应用采用Holo主题。所以我们可以简单地认为Android Design说的就是Holo主题。但是这种主题只适用于移动设备,在其他平台上略显突兀。

所以从Android 5.0(Api 21)开始,Google又推出了Material Design,中文翻译过来叫“材料设计语言”。其实它还有个名字叫Google Design,通过名字可以看出这种设计语言旨在为手机、平板电脑、台式机和“其他平台”提供更一致、更广泛的“外观和感觉”。MD崇尚的就是图层的扁平化,所有的图层像纸或者卡片一样重叠在一起,所以在5.0中有了RecyclerView和CardView。图层之间有间隔,所以在5.0中有了translationZ和elevation两个属性。同时也规范了Android的运动元素,界面上的每个元素不是无故产生的,元素的产生必有出处,同时每个图层的产生和消失都有方向的约定,从哪出来就要从哪回去。这也是为什么5.0中会有Ripple,Circular Reveal,Activity Transition。

有关MD的设计思想,可以百度或者参考Google的官方文档。本篇主要站在Android开发者的角度介绍Android开发中有关上述的几种主题的引用方式。



如何引用系统主题

我们都知道主题的指定实际上实在styles.xml文件中。现在用Android Studio建一个工程,styles.xml默认是这个样子的:

<resources> <!-- Base application theme. --> <style name="AppTheme" parent="Theme.AppCompat"> <!-- Customize your theme here. --> <item name="colorPrimary">@color/colorPrimary</item> <item name="colorPrimaryDark">@color/colorPrimaryDark</item> <item name="colorAccent">@color/colorAccent</item> </style> </resources>

可以看到我们的主题默认继承了Theme.AppCompat。那么这个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版本的主题。

最后一句话怎么理解,举个例子,如果在我们在Api 24的sdk下进行开发,设置我们的应用targetSdkVersion=16,应用的资源目录下建立value-16,这是针对4.4以上平台的资源目录,在styles.xml中我们继承android:Theme.Material,这很明显是在5.0系统之上才能用的。虽然Android Studio会给出提示,但可以编译通过。现在我们把App放在一台4.4的机器上跑,这时系统是找不到android:Theme.Material这个主题的。那么系统就会看targtSdkVersion,发现是16,所以系统就会将App的主题设置为Holo的。如果我们其他的所有配置都不变,只把targetSdkVersion改成9,系统就会把App的主题设置为android:Theme的主题。这时如果把targetSdkVersion改成24,4.4的机器是不支持24的,那么出来的效果依然是android:Theme.Holo主题。



Theme.AppCompat

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

我们先来说Theme.AppCompat,这个主题可以让5.0以下的系统使用Material主题。我们只需要让我们的系统主题继承Theme.AppCompat即可。只需要指定这个就OK了,是不是很简单。

有必要说的是,使用了Theme.AppCompat之后,targetSdkVersion就不受影响了。继续拿上一节的例子说,在Api24 Sdk下开发,targtSdkVersion=9,跑在4.4的机器上,你会发现依然是Material主题。

所以可以总结出,应用使用了Theme.AppCompat主题,不论我们的targetSdkVersion指定为多少,跑在任意版本的系统上都会呈现出Material主题。



AppCompatActivity的主题

现在轮到介绍AppCompatActivity,它是替换ActionBarActivity的。主要是为了给不同平台兼容ActionBar,并支持ToolBar等。AppCompatActivity的特性不是本篇的讨论重点,感兴趣了同学可以自行查阅资料。针对主题这个话题,我们只需要知道,AppCompatActivity(包括ActionBarActivity)的子Activity必须使用Theme.AppCompat或Theme.AppCompat的子主题,如果不是,编译时不会给出任何警告,但运行时会抛出异常,

java.lang.IllegalStateException: You need to use a Theme.AppCompat theme (or descendant) with this activity.

所以我们使用AppCompatActivity的时候需要注意。不过如果我们的Activity使用了Theme.AppCompat主题,但不一定要继承AppCompatActivity。



总结

通过以上的介绍,我们进行一个总结。

  • 目前的系统有四种基本主题:
  • android:Theme
  • android:Theme.Holo ( >= Api 11)
  • android:Theme.Material( >= Api 21)
  • Theme.AppCompat

其他的主题,诸如xxx.Light, xxx.Light.Notitle等都是继承自这四个基本主题,可以根据项目需要自行引用。

  • 如果需要在做到全系统兼容Material Design,那么继承了Theme.AppCompat,这样不论我们的targetSdkVersion指定为多少,跑在任意版本的系统上都会呈现出Material主题。
  • AppCompatActivity依赖Theme.AppCompat,Theme.AppCompat不依赖AppCompatActivity。
  • 如果我们要在不同版本的系统上设置不同的主题,那么需要创建不同版本的values-vX目录,根据需要继承android:Theme、android:Theme.Holo、android:Theme.Material。这样系统会根据values-vX找到相应的主题。
  • 如果系统在运行时没有找到主题,那么会根据targetSdkVersion设置不同的主题。假如我们指定的targetSdkVersion超过了系统支持的版本,系统会设置所支持的最高版本主题。