在写代码的时候,经常遇到自定义的style,有的用来设置属性,有的用来设置主题,搞的自己云里雾里,因此在心底暗暗发誓,等到空闲的时候,一定好好学学android中的style的究竟是个什么东西,到底有什么用处。于是今天来了机会,到网上学习了一个别人写的相关的文章。虽然有的地方还是有些不太懂,但是起码算是对style有了一个初步的理解和使用。在此,特别记录下自己的学习收获,好记性不如烂笔头。由于本人是初学者,文中如果有不合理的地方,恳请大家批评指正。android进阶的道路上,一起坚持学习!
一、前言
android中的style设计,其实主要是程序开发者来自定义一种自己需要的样式,或者叫风格。它应用主要分为两个方面
(1)Theme,即自定义主题,这是针对窗体级别的,给一个窗体设计一个风格或者叫样式。
(2)属性等的设置,这主要是针对窗体元素级别的,比如给一个view或者布局设定样式。
另一方面,由于style天生就可以集成属性,因此它的另一个用途是也可以减少代码的复用。比如如果你的app中所有的文字都必须设定相同的大小,和相同的颜色,那么在具有文字的控件上,你不必一一为他们设定这些属性,可以将要设置的大小和颜色集成到style文件里,然后引用即可。如果你是第一次系统的了解style,可能这些话你还不是很理解,没关系接着往下看就可以了。因为不看实际的代码,是很难将这些细节性的东西说清楚的。下面就是一些实际例子,希望读者可以跟我一起编写。
二、为view编写style
下面我们就来编写一个极为简单的例子来看看怎么给一个TextView自定义style。
新建一个项目,在res/values文件夹下,建立文件styles.xml。编写其中的代码如下:
1 <resources xmlns:android="http://schemas.android.com/apk/res/android"> 2 3 <!-- 4 Base application theme, dependent on API level. This theme is replaced 5 by AppBaseTheme from res/values-vXX/styles.xml on newer devices. 6 --> 7 <style name="AppBaseTheme" parent="android:Theme.Light"> 8 <!-- 9 Theme customizations available in newer API levels can go in 10 res/values-vXX/styles.xml, while customizations related to 11 backward-compatibility can go here. 12 --> 13 </style> 14 15 <!-- Application theme. --> 16 <style name="AppTheme" parent="AppBaseTheme"> 17 <!-- All customizations that are NOT specific to a particular API-level can go here. --> 18 </style> 19 20 <style name="MyText"> 21 <item name ="android:text">我是自定义style</item> 22 <item name="android:textSize">25sp</item> 23 <item name="android:textColor">#008</item> 24 </style> 25 26 </resources>
注意,绿色背景的部分,即第20行到23行是我们新写的一个style。可以看到,在这个样式中,我们将文本大小指定为25sp,恩本的颜色指定为#008。需要说明的是
(1)MyText是我们定义的这个样式的名称,它是可以任意命名的。
(2)item标签里的name,等号里内容是控件所带的属性,即attr。一般使用的都是控件自带的。当然也可以使用你给控件自定义的attr,但这是后话。
这个样式我们已经定义好了,下面我们在activity_main.xml中添加一个TextView控件,就可以给这个控件指定我们指定的样式了。如下:
1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 2 xmlns:tools="http://schemas.android.com/tools" 3 android:layout_width="match_parent" 4 android:layout_height="match_parent" 5 > 6 7 <TextView 8 android:id="@+id/tv" 9 android:layout_width="wrap_content" 10 android:layout_height="wrap_content" 12 style="@style/MyText"/> 13 14 </RelativeLayout>
代码是不是很简单,这样子,只需要第12行一句话,就同时指定了文本的大小和颜色,而且还设置了文本。MainActivity中已经自动加载了这个布局。我们运行一下,效果如下:
怎么样,是不是对style的使用有一点感觉了呢?当然了,还有一些琐碎的知识,下面来讲。
(1)优先级别实验
比如我们虽然在定义的样式中,设定了文本,但是如果我们在xml中,重复给TextView设置文本了呢?现将activity_main.xml中的代码修改如下:
1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 2 xmlns:tools="http://schemas.android.com/tools" 3 android:layout_width="match_parent" 4 android:layout_height="match_parent" 5 > 6 7 <TextView 8 android:id="@+id/tv" 9 android:layout_width="wrap_content" 10 android:layout_height="wrap_content" 11 android:text="我被修改了" 12 style="@style/MyText"/> 13 14 </RelativeLayout>
可以看到,第11行,我们给TextView指定了另外一个文本。现在运行程序,效果如下:
文本信息显示的是我们所修改的文本,而不是style里指定的文本。其他的我就不再实验了。结论就是
在使用style的时候,已经设定的属性的级别比style指定的要高,如果发生重复,以已经设定的为准
(2)style也是可继承的
style也是可以继承,使用parent来指定它的父style是哪一个。比如我们修改styles.xml中的代码如下:
1 <resources xmlns:android="http://schemas.android.com/apk/res/android"> 2 3 <!-- 4 Base application theme, dependent on API level. This theme is replaced 5 by AppBaseTheme from res/values-vXX/styles.xml on newer devices. 6 --> 7 <style name="AppBaseTheme" parent="android:Theme.Light"> 8 <!-- 9 Theme customizations available in newer API levels can go in 10 res/values-vXX/styles.xml, while customizations related to 11 backward-compatibility can go here. 12 --> 13 </style> 14 15 <!-- Application theme. --> 16 <style name="AppTheme" parent="AppBaseTheme"> 17 <!-- All customizations that are NOT specific to a particular API-level can go here. --> 18 </style> 19 20 <style name="MyText"> 21 <item name ="android:text">我是自定义style</item> 22 <item name="android:textSize">25sp</item> 23 <item name="android:textColor">#008</item> 24 </style> 25 <style name="My" parent="@style/MyText"> 26 27 </style> 28 29 </resources>
在代码的第25行,新建了一个style,名字为My,它继承了MyText。但是它自己却是什么都没有添加。现在我们来使用这个style来看看。修改activity_main.xml,如下:
1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 2 xmlns:tools="http://schemas.android.com/tools" 3 android:layout_width="match_parent" 4 android:layout_height="match_parent" 5 > 6 7 <TextView 8 android:id="@+id/tv" 9 android:layout_width="wrap_content" 10 android:layout_height="wrap_content" 11 style="@style/My"/> 12 13 </RelativeLayout>
可以看到我们这里使用了名称为My的这个style。然后运行程序,效果如下:
跟使用MyText的style是一样的效果。因此继承会保留父style的风格,同时也会有自己的风格。
(3)style中使用自定义的attr
关于自定义的attr,如果你不了解,可以参看我的上一篇文章:http://www.cnblogs.com/fuly550871915/p/4907048.html
前面我们说过,style的item标签中的name字段就是控件所带的属性名称。一般都是使用android系统自带的属性。但是我们也知道,attr也是可以自定义的。那么如果我们有自定义的attr,怎么集成到style中呢?其实也很简单。依旧以上面的代码为基础。继续讲解这个例子。
首先在values下建立attrs.xml,将我们的自定义属性构建出来。代码如下:
1 <?xml version="1.0" encoding="utf-8"?> 2 <resources> 3 <declare-styleable name="MyView"> 4 <attr name="textColor" format="color" /> 5 <attr name="textSize" format="dimension" /> 6 </declare-styleable> 7 </resources>
从代码中看到,我们自定义了自己的属性textColor和textSize。下面我们为TextView设定样式,使用的就是我们自定义的属性。styles.xml的代码修改如下:
1 <resources xmlns:android="http://schemas.android.com/apk/res/android"> 2 3 <!-- 4 Base application theme, dependent on API level. This theme is replaced 5 by AppBaseTheme from res/values-vXX/styles.xml on newer devices. 6 --> 7 <style name="AppBaseTheme" parent="android:Theme.Light"> 8 <!-- 9 Theme customizations available in newer API levels can go in 10 res/values-vXX/styles.xml, while customizations related to 11 backward-compatibility can go here. 12 --> 13 </style> 14 15 <!-- Application theme. --> 16 <style name="AppTheme" parent="AppBaseTheme"> 17 <!-- All customizations that are NOT specific to a particular API-level can go here. --> 18 </style> 19 20 21 <style name="mytext"> 22 <item name ="android:text">我是自定义style</item> 23 <item name="com.fuly.kun:textSize">25sp</item> 24 <item name="com.fuly.kun:textColor">#008</item> 25 </style> 26 27 </resources>
从绿色的代码,我们发现其实将自定义的attr集成到style中,十分简单。只需:
name中的内容改成完整的包名,然后挂上我们自定义的属性即可。比如这个样式是给TextView定义的,那么这里的包名应该就是TextView所在的那个包。
好了,剩下的与上面的使用一样,为了让你看的明白。我就把activity_main.xml中的代码也贴出来吧,如下:
1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 2 xmlns:tools="http://schemas.android.com/tools" 3 android:layout_width="match_parent" 4 android:layout_height="match_parent" 5 > 6 7 <TextView 8 android:id="@+id/tv" 9 android:layout_width="wrap_content" 10 android:layout_height="wrap_content" 11 style="@style/mytext"/> 12 13 </RelativeLayout>
然后运行程序,效果如下:
好了,相信通过上面的讲解,你对style的这方面使用已经有一定的理解了吧。其实style使用很灵活,只要我们的view或者布局,带有什么属性,它就可以集成什么属性,从而设定成风格。
三、style的Theme使用
在这一部分,来说一说style用来设置主题。这其实跟style来设计view的风格是一样的,唯一的区别就是item中的内容应该写成与主题相关的语句而已。你也可以继承一个style设计好的主题或者是系统自带的主题,然后来修改它。下面我们来看一个小例子吧。
新建一个项目,然后直接修改它的activity_main.xml语句。如下:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context=".MainActivity" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="我是自定义的主题" /> </RelativeLayout>
代码太简单了,什么都没改,只是将TextView的文本信息改为了“我是自定义的主题”而已。然后修改styles.xml里的代码,如下:
1 <resources xmlns:android="http://schemas.android.com/apk/res/android"> 2 3 <!-- 4 Base application theme, dependent on API level. This theme is replaced 5 by AppBaseTheme from res/values-vXX/styles.xml on newer devices. 6 --> 7 <style name="AppBaseTheme" parent="android:Theme.Light"> 8 <!-- 9 Theme customizations available in newer API levels can go in 10 res/values-vXX/styles.xml, while customizations related to 11 backward-compatibility can go here. 12 --> 13 </style> 14 15 <!-- Application theme. --> 16 <style name="AppTheme" parent="AppBaseTheme"> 17 <!-- All customizations that are NOT specific to a particular API-level can go here. --> 18 </style> 19 <style name="mytheme"> 20 <item name="android:windowNoTitle">true</item> 21 <item name="android:textColor">#00ff00</item> 22 </style> 23 24 </resources>
绿色背景的部分是我自定义了一个主题,该主题隐藏窗口标题栏,且给文字设置了颜色。你可能会郁闷,我是怎么知道wndowNoTitle这个窗体属性的呢??其实很简单,这是android系统自带的Theme.xml文件,我们只要查看它就可以发现它的主题里都有什么属性了。上面的代码的第7行,不是有parent="android:Theme.Light"这句话嘛,我们按住ctrl建,然后鼠标点击Theme就可以在eclipse中查看Theme.xml的源代码了(前提是你的eclipse与android源码先关联起来)。然后在Theme.xml中,就可以找到窗体的属性了。如果你的elipse没有与android源码关联,没关系,我把我找到的贴出来给你看,如下:
1 <!-- Window attributes --> 2 <item name="windowBackground">@android:drawable/screen_background_selector_dark</item> 3 <item name="windowFrame">@null</item> 4 <item name="windowNoTitle">false</item> 5 <item name="windowFullscreen">false</item> 6 <item name="windowOverscan">false</item> 7 <item name="windowIsFloating">false</item> 8 <item name="windowContentOverlay">@null</item> 9 <item name="windowShowWallpaper">false</item> 10 <item name="windowTitleStyle">@android:style/WindowTitle</item> 11 <item name="windowTitleSize">25dip</item> 12 <item name="windowTitleBackgroundStyle">@android:style/WindowTitleBackground</item> 13 <item name="android:windowAnimationStyle">@android:style/Animation.Activity</item> 14 <item name="android:windowSoftInputMode">stateUnspecified|adjustUnspecified</item> 15 <item name="windowActionBar">false</item> 16 <item name="windowActionModeOverlay">false</item> 17 <item name="windowCloseOnTouchOutside">false</item> 18 <item name="windowTranslucentStatus">false</item> 19 <item name="windowTranslucentNavigation">false</item>
通过上面的源代码我们就可以编辑其他的窗体属性了。
那么怎么使用这个主题呢?有两种方式。
第一种,在Manifest.xml文件中使用
如果我们嵌在application标签下,则整个app都是这个主题。如果嵌在某个活动下,则只有这个后动是这个主题。在这里我们嵌在活动中,修改Manifest.xml中的代码如下。为了让你看的清楚,我还是贴出完整代码吧,尽管修改的只有一句:
1 <?xml version="1.0" encoding="utf-8"?> 2 <manifest xmlns:android="http://schemas.android.com/apk/res/android" 3 package="com.fuly.kun" 4 android:versionCode="1" 5 android:versionName="1.0" > 6 7 <uses-sdk 8 android:minSdkVersion="8" 9 android:targetSdkVersion="18" /> 10 11 <application 12 android:allowBackup="true" 13 android:icon="@drawable/ic_launcher" 14 android:label="@string/app_name" 15 android:theme="@style/AppTheme" > 16 <activity 17 android:name="com.fuly.kun.MainActivity" 18 android:label="@string/app_name" 19 android:theme="@style/mytheme" > 20 <intent-filter> 21 <action android:name="android.intent.action.MAIN" /> 22 23 <category android:name="android.intent.category.LAUNCHER" /> 24 </intent-filter> 25 </activity> 26 </application> 27 28 </manifest>
代码第19行绿色部分,我们给MainActivity这个活动指定为我们自定义的主题了。下面运行程序,效果如下:
我们看,确实自定义的主题生效了,没有标题栏目,且字体颜色为绿色。
第二种:在代码中指定主题。
我们抹去上面的修改,在MainActivity中修改如下:
1 package com.fuly.kun; 2 3 import android.os.Bundle; 4 import android.app.Activity; 5 import android.view.Menu; 6 7 public class MainActivity extends Activity { 8 9 10 protected void onCreate(Bundle savedInstanceState) { 11 super.onCreate(savedInstanceState); 12 setTheme(R.style.mytheme); 13 setContentView(R.layout.activity_main); 14 15 } 16 17 18 19 }
代码也很简单,在第12行,使用一句setTheme方法来设置我们的主题即可,但是注意,必须要在setContentView执行之前设置。然后运行程序,效果图如下:
这里和前面有一个细微的差别,就是背景变成了白色。我也不知道这是为什么,应该是和view的绘制流程有关吧?至于我们自定义的主题效果,都达到了。
(1)使用继承
我们接着上面的代码往下写。来做一个继承的实验。一切都不变,即还是在MainActivity中使用我们自定义的主题,但是我们自定义的主题要修改如下,即修改styles.xml如下:
1 <resources xmlns:android="http://schemas.android.com/apk/res/android"> 2 3 <!-- 4 Base application theme, dependent on API level. This theme is replaced 5 by AppBaseTheme from res/values-vXX/styles.xml on newer devices. 6 --> 7 <style name="AppBaseTheme" parent="android:Theme.Light"> 8 <!-- 9 Theme customizations available in newer API levels can go in 10 res/values-vXX/styles.xml, while customizations related to 11 backward-compatibility can go here. 12 --> 13 </style> 14 15 <!-- Application theme. --> 16 <style name="AppTheme" parent="AppBaseTheme"> 17 <!-- All customizations that are NOT specific to a particular API-level can go here. --> 18 </style> 19 <style name="mytheme" parent="@android:style/Theme.Dialog"> 20 <item name="android:windowNoTitle">true</item> 21 <item name="android:textColor">#00ff00</item> 22 </style> 23 24 </resources>
我们只是修改了第19行,让这个主题继承自系统自带的一个主题而已。继承的是对话框。然后我们运行程序,效果图如下:
自定义主题的效果生效了,活动变成了一个对话框,且没有标题,字体颜色也是我们设定的。可见使用继承,是十分便利的。
(2)使用系统自带的主题
使用系统自带主题,具体的实验我就不做了。相应的使用方式也有上面两种,你要么在manifest.xml文件中指定,要么在代码中指定。但是要记住:
在xml文件中,使用系统自带主题,要使用语句:
android:theme="@android:style/Theme.Dialog"
style/后面的内容你可以更改为系统自带的其他主题
如果使用自己自定义的,只需要@style即可:
android:theme="@style/CustomTheme"
下面总结一下,常用的android自带的主题:
android中自带的主题(theme)的集锦:
•android:theme="@android:style/Theme.Dialog" 将一个Activity显示为对话框模式
•android:theme="@android:style/Theme.NoTitleBar" 不显示应用程序标题栏
•android:theme="@android:style/Theme.NoTitleBar.Fullscreen" 不显示应用程序标题栏,并全屏
•android:theme="@android:style/Theme.Light" 背景为白色
•android:theme="@android:style/Theme.Light.NoTitleBar" 白色背景并无标题栏
•android:theme="@android:style/Theme.Light.NoTitleBar.Fullscreen" 白色背景,无标题栏,全屏
•android:theme="@android:style/Theme.Black" 背景黑色
•android:theme="@android:style/Theme.Black.NoTitleBar" 黑色背景并无标题栏
•android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen" 黑色背景,无标题栏,全屏
•android:theme="@android:style/Theme.Wallpaper" 用系统桌面为应用程序背景
•android:theme="@android:style/Theme.Wallpaper.NoTitleBar" 用系统桌面为应用程序背景,且无标题栏
•android:theme="@android:style/Theme.Wallpaper.NoTitleBar.Fullscreen" 用系统桌面为应用程序背景,无标题栏,全屏
•android:theme="@android:style/Translucent" 半透明效果
•android:theme="@android:style/Theme.Translucent.NoTitleBar" 半透明并无标题栏
•android:theme="@android:style/Theme.Translucent.NoTitleBar.Fullscreen" 半透明效果,无标题栏,全屏
•android:theme="@android:style/Theme.Panel"
•android:theme="@android:style/Theme.Light.Panel"