style和theme都是用于定义控件的显示样式,只不过style只能作用于单独的一个控件;theme虽然也是style的一种,但theme作用的是整个APP或某个界面或一组控件:如果你的theme用在清单文件的application节点下,那么这个theme就作用于整个APP;如果用在某个清单文件的activity节点下,它就只作用于这个界面。

  一、创建并引用style
  你的style一般定义在项目的res/values/styles.xml文件中,如下:





<?xml version="1.0" encoding="utf-8"?>
<resources>
    <style name="GreenText" parent="TextAppearance.AppCompat">
        <item name="android:textColor">#00FF00</item>
    </style>
</resource>

  在style节点中申明的是这个style的名称和其继承的父类style,item节点中申明的是要修改的控件属性名字和属性值,只要能在布局文件中定义出来的控件属性同样都可以定义在item节里。然后通过如下的形式来为一个控件引用这个style

<TextView
    style="@style/GreenText"
    ... />

  二、继承并修改系统style
  上面我们知道,继承一个style,只需要在style节点中通过parent指定父类style就可以了。这里的父类style有两种来源,一种是安卓系统默认的style,另一种就是v4或v7支持包下的style,一般建议用支持包下的style,因为这些支持包下的style在4.0以上兼容性更好。以下是引用系统默认的style:





<style name="GreenText" parent="@android:style/TextAppearance">
    <item name="android:textColor">#00FF00</item>
</style>

  以下是引用支持包下的style:





<style name="GreenText" parent="TextAppearance.AppCompat">
    <item name="android:textColor">#00FF00</item>
</style>

  通过对比我们发现:系统默认的style一般都以@android:style开头,而支持包下的style一般会包含Appcompat,这就好区分了。
  这里有一个小问题,如果我们自定义了自己的一个style,有时候我们需要只改动其中一项或几项属性,用于新的控件,怎样改比较优雅呢?其实除了上面的parent方式,我们还可以通过以下方式来实现:





<style name="GreenText.Large">
    <item name="android:textSize">22dp</item>
</style>

  其中,GreenText就是我们自定义的父类style名称,句点后的Large就是当前style的真正名称。这样,当前的style就具有了GreenText的所有样式,只不过其中的字体大小被改成了22dp。需要注意的是:这种继承方式仅仅限于继承我们自定义的样式,如果是安卓默认的样式或支持包中的样式则不能这样。另外,如果通过这样的方式继承了一个我们的自定义样式,又通过parent方式继承了新的style,那么新的style将会替换掉前者的style。例如:





<style name="GreenText.Large" parent="新的style">
    <item name="android:textSize">22dp</item>
</style>

  三、创建并引用theme
  整个APP引用:





<manifest ... >
    <!--Theme.AppCompat为夜间主题-->
    <application android:theme="@style/Theme.AppCompat" ... >
    </application>
</manifest>

  某个activity引用:





<manifest ... >
    <application ... >
        <!--Theme.AppCompat.Light为日间主题-->
        <activity android:theme="@style/Theme.AppCompat.Light" ... >
        </activity>
    </application>
</manifest>

  其中,activity中的theme将会覆盖掉application中的theme对该界面的作用。其实,从android5.0和v22.1的支持包开始,theme也可以在布局文件中通过android:theme方式单独作用于一个控件的,只不过不经常这样用。

  创建、继承theme的方式跟创建、继承style的方式是一样的,当我们创建了一个新的项目时,as会为我们生成一个默认的theme并在清单文件application节点中默认引用了,如下:

<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <!-- colorPrimary控制的是app bar的颜色和其他主要部分的颜色 -->
    <item name="colorPrimary">@color/colorPrimary</item>
    <!-- colorPrimaryDark主要控制的是手机状态栏的颜色-->
    <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
    <!-- colorAccent整体控制整个APP中checkbox和radiubutton等控件选中后的默认颜色和某些文本的颜色-->
    <item name="colorAccent">@color/colorAccent</item>
    <!--新布局文件创建时默认的背景色-->
    <item name="android:windowBackground">@color/activityBackground</item>
</style>

  我们可以在上面修改想要的主题,也可以增加新的item属性,例如是否隐藏app bar等。
  
  四、使用特定android版本的新theme
  比如说你现在项目里已有一个名字为BaseAppTheme的主题,现在android5.0以上新增了某些新的主题属性,你想让你的APP运行在5.0以上的设备时能够使用这些新的主题。可以通过以下方式实现:
  1、在res/values/styles.xml 文件中定义一个主题继承BaseAppTheme:
  

<resources>
    <!-- 这是所有版本都可以使用的基础主题 -->
    <style name="BaseAppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <item name="colorPrimary">@color/primaryColor</item>
        <item name="colorPrimaryDark">@color/primaryTextColor</item>
        <item name="colorAccent">@color/secondaryColor</item>
    </style>

    <!-- 在清单文件中引用的主题 -->
    <style name="AppTheme" parent="BaseAppTheme" />
</resources>

  2、新建res/values-v21/styles.xml文件并定义AppTheme主题,继承BaseAppTheme,新增主题属性。其中的v21为API版本,即只有5.0以上的系统才使用的主题属性:
  

<resources>
    <style name="AppTheme" parent="BaseAppTheme">
        <!--全局的activity切换时是否使用过渡动画-->
        <item name="android:windowActivityTransitions">true</item>
        <!--全局的activity进入动画-->
        <item name="android:windowEnterTransition">@android:transition/slide_right</item>
        <!--全局的activity退出动画-->
        <item name="android:windowExitTransition">@android:transition/slide_left</item>
    </style>
</resources>

  五、为某种类型的控件统一全局的样式
  无论是android系统中还是支持包中的每一个控件,都有一个默认的样式,例如一个Button的默认样式叫Widget.AppCompat.Button,你可以为布局文件中的某个Button单独使用该样式,例如:
 

<Button
    style="@style/Widget.AppCompat.Button.Borderless"
    ... />

  你也可以在APP的主题中为所有Button统一样式,例如:

<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <item name="buttonStyle">@style/Widget.AppCompat.Button.Borderless</item>
    ...
</style>

   扩展:为所有Textview统一样式可以用textAppearance属性;为所有Checkbox统一样式用checkboxStyle属性;为所有RadioButton统一样式用radioButtonStyle属性等等。这些控件属性默认都已Widget.Appcompat开头。