本文将要着重讲解的Android资源大致可以分为三类:
1. values资源
- string 字符串资源
- color 颜色资源
- dimen 尺寸资源
- array 数组资源
- style 样式资源
- theme 主题资源
2. drawable资源
- 图片资源
- StateListDrawable资源
- LayerDrawable资源
- ShapeDrawable资源
- ClipDrawable资源
3.ColorStateList资源
--以下:正文部分-- Android的设计哲学为:设计与表现分离。 这样有利于程序的解耦。所以我们才可以在XML文件中定义各种资源类型,并在其他的xml文件或java代码中进行引用。
1.1 String资源:
字符串资源所对应的xml文件位于/res/values/
目录下。 其默认名为strings.xml
对应于R类中的内部类的名称:R.string 文件的根元素为resources
:
定义:
复制代码 Hello World Hello World Hi there
引用:
一般我们都是在同一个包下的其他xml文件中引用字符串资源: 比如在TextView中引用之前定义的字符串:
复制代码
android:text="@string/text_name"
所表达的 正是引用同一包下字符串资源文件中名为text_name的字符串资源。 当然,如果是引用不同包下的资源,可则只需在@和string之间加上包名。 事实上,在xml代码中使用资源的通用完整语法格式正是: @[<package_name>:]<resource_type>/<resource_name>
其中中括号代表选填,尖括号代表必填。
1.2 Color资源:
与字符串资源类似,我们可以事先在xml文件中定义,并在之后对其进行引用。 颜色资源所对应的xml文件位于/res/values/
目录下。 其默认名为colors.xml
对应于R类中的内部类的名称:R.color 文件的根元素为resources
:
定义:
复制代码 #aaa #ffffff #454647
引用:
复制代码
方法与对string资源的引用大同小异,不再赘述。
1.3 dimen资源:
dimen是dimension的缩写,表示尺寸。如果我们的布局中有多个view需要指定相同的尺寸,那么我们可以事先在dimen资源中对该尺寸进行定义,之后便可以很方便地复用。 dimen资源所对应的xml文件位于/res/values/
目录下。 其默认名为dimens.xml
对应于R类中的内部类的名称:R.dimen 文件的根元素为resources
:
定义:
复制代码 60dp 60dp
引用:
复制代码
1.4 array资源:
数组资源所对应的xml文件位于/res/values/
目录下。 其默认名为arrays.xml
对应于R类中的内部类的名称:R.array 文件的根元素为resources
: 不同的是,arrays.xml文件中可以定义三种不同类型的子元素:
- 普通类型的数组,比如Drawable数组,用
<array.../>
来表示。 - 字符串类型的数组,用
<string-array.../>
来表示。 - 整型数组,用
<integer-array.../>
来表示。
1.4.1 typedArray定义:
复制代码 - @color/colorPrimary
- @color/colorAccent
- @color/colorPrimaryDark
- @color/colorBlack
- @color/colorCyan
- @color/colorGreen
以上在/res/values/arrays.xml
中定义了一个普通类型的数组。这种类型的数组也叫做TypedArray,其中的数组项可以定义Drawable对象等。
在数组的每一项中都引用了/res/values/colors/
中定义的颜色资源。 接下来可以在java代码中对该数组中的资源加以运用。比如我们可以在布局文件中定义一个文本框,再定义一个按钮,点击按钮实现文本框背景色的轮播:
public class MainActivity extends AppCompatActivity { int counter = 0; TextView tv; Button bn; TypedArray typedArray;//注意:调用typedArray的getColor()方法时//如果不加这个@SuppressWarning标签就会报错 @SuppressWarnings("ResourceType") @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); tv = (TextView) findViewById(R.id.text_view); bn = (Button) findViewById(R.id.bn);//通过getResources()方法获取到Resources,并将引用赋给res Resources res = getResources();//向obtainTypedArray()方法中,传入R.array.color_array//返回一个TypedArray对象,命名typedArray//里面存储的是数组中的颜色资源 typedArray = res.obtainTypedArray(R.array.color_array); bn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { int color = typedArray.getColor(counter%typedArray.length(), 0); tv.setBackgroundColor(color); counter++; } }); }}复制代码
效果
注:TypedArray在自定义view时也有应用,限于篇幅,本文不深入讲解。
1.4.2 string-array定义:
复制代码 - Android
- Ios
- Swift
- Java
- C##
- @string/text_content
方法是类似的。只不过根元素写的是string-array
。 其中的字符串既可以直接定义值(前5项),也可以引用事先定义好的字符串(最后一项)。 应用 比如我们可以在布局文件中定义一个ListView,然后在其entries
属性中引用该数组:
复制代码
效果
1.4.3 integer-array定义:
与string-array的定义类似,只是将string资源变成了integer类型的资源。
复制代码 - 2
- 4
- 8
- 16
应用 简单起见,我们同样也可以在ListView中对该数组进行引用:
复制代码
效果
1.5 style资源:
style资源指的是Android的样式资源。 同样在/res/values/
目录下定义 style资源文件的根元素也是resources
。 resources
下可以包含多个<style.../>
子元素,每个style
子元素可以定义一个样式,style
标签可以指定两个属性:
name:
指定样式的名称;parent:
指定该样式所继承的父样式。与java中的继承类似:当继承某个父样式时,该样式将会获得父样式中定义的全部样式。同样地,当前样式也可以覆盖父样式中指定的格式。<style.../>
元素内可以包含多个<item.../>
子元素,每个都可以定义一个格式项。
复制代码
举例:
复制代码
我们可以为两个button分别指定定义的style1和style2:
复制代码
效果:
可以看到,第二个button所引用的style2的parent属性指定的是style1。 所以style2继承了style1属性。但是style2中也重写了style1的“textAllCaps”属性,所以第二个button所显示的text默认为大写。 当然,style2继承了style1后,也可以定义自己属性,如以上的<item name="android:background">#666</item>
。 如此一来,就可以事先定义好一组样式的集合,然后将该style一次性应用给某个组件。 1.6 theme资源:
theme资源与style资源类似。 同样在/res/values/
目录下定义,根元素同样是resource
,同样用<style.../>
来定义。 区别在于:主题应该作用于整个应用中的所有Activity或者作用于某个指定的Activity。且主题影响的应该是窗口的标题、边框等属性:
复制代码
使用该主题:
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setTheme(R.style.my_theme); ...复制代码
默认情况下,活动的顶部:
设置
- true
复制代码
之后,活动的顶部:
如果想要让应用中的所有窗口都应用刚才定义的my_theme
主题,则只需要在清单文件中的<application.../>
元素下添加android:theme="@style/my_theme">
即可。
--以上:第一部分--
2.1 图片资源:
图片资源可谓是最简单的drawable资源。只需要把Android认可的图片资源(.png,.jpg,*.gif)放在/res/drawable-xxx
目录下即可。Android SDK在编译应用时会自动加载图片资源,并在R类中生成对该资源的索引。如此,图片资源就和values资源一样,可以通过 @[<package_name>:]drawable/文件名
的方式在xml代码中被访问了。 如果想要在java代码中访问到实际的图片Drawable对象,而不是R类中int类型的索引,可以利用Resources类提供的```Drawable getDrawable(int id)方法。该方法可以根据R类中的id获取到实际的Drawable对象。
2.2 StateListDrawable资源 顾名思义,StateList就是一个state(状态)的集合。它可以用来组织多个Drawable对象,并让使用了该StateListDrawable的组件根据自身不同的状态来自动切换至相应的Drawable。 定义:
- 在Drawable文件夹下,右键new一个新的drawable resource file
- 根元素为
selector
,可以理解为状态选择器 - 根元素下可以包含多个
<item.../>
并可以为其指定如下属性:
- android:color 或 android:drawable: 指定颜色或者drawable对象
- android:state_xxx: 指定一个特定的状态
举例: 比如我们想让一个button在按下时候和未被按下的时候的背景颜色不同,可以这样写:
复制代码
在button中引用这个StateListDrawable:
复制代码
效果:
当然,以上只是StateListDrawable所支持的其中两个状态。 完整的状态列表如下:属性值 | 含义 |
---|---|
android:state_active | 表示是否处于激活状态 |
android:state_checkable | 表示是否处于可勾选状态 |
android:state_checked | 表示是否处于已勾选状态 |
android:state_enabled | 表示是否处于可用状态 |
android:state_first | 表示是否处于开始状态 |
android:state_focused | 表示是否处于已得到焦点状态 |
android:state_last | 表示是否处于结束状态 |
android:state_middle | 表示是否处于中间状态 |
android:state_pressed | 表示是否处于被按下状态 |
android:state_selected | 表示是否处于被选中状态 |
android:state_window_focused | 表示窗口是否处于已得到焦点状态 |
2.3 LayerDrawable资源
LayerDrawable顾名思义,就表现得和图层差不多。可以在根元素layer-list
中定义多个drawable对象,并且像帧布局那样将各个对象堆叠起来。最后定义的对象处于最上面。 相同的时,根元素下同样可以包含多个<item.../>
子项,并可以在其中定义drawable对象的引用。同时还可以设置top
,bottom
,right
以及left
属性来设置堆叠时,drawable对象向各个方向的偏移量(offset)。 不同的是,<item.../>
中的各个子项除了指定偏移量之外,还可以指定id属性。另外,根据官方说法:
默认情况下,所有可绘制项都会缩放以适应包含视图的大小。因此,将图像放在图层列表中的不同位置可能会增大视图的大小,并且有些图像会相应地缩放。为避免缩放列表中的项目,请在 元素内使用 元素指定可绘制对象,并且对某些不缩放的项目(例如 "center")定义重力。例如,以下 定义缩放以适应其容器视图的项目:
<item android:drawable="@drawable/image" />
比如我们要让两个图标堆叠在一起并且在ImageView中显示,可以这样写: 先定义一个layer_drawable.xml
文件:
复制代码
然后在ImageView中引用:
复制代码
效果:
2.4 ShapeDrawable资源
简单来说,Android的ShapeDrawable让我们可以不用做图就能实现各种简单的几何图形,并能控制圆角、填充颜色、边框、内边距、半径等各种属性。这样我们在为某个组件(比如TextView)指定背景时,就方便多了。 定义: ShapeDrawable的根元素是<shape.../>
。 其中android:shape="
属性有4中值可以选:line, rectangle, oval, ring。 举例: 下面分别定义了两个ShapeDrawable: shape1.xml
" class="hljs ">复制代码
和shape2.xml
:
复制代码
然后将他们分别设置为两个TextView组件的背景,效果如下:
当然,不止是TextView可以用ShapeDrawable作为背景,支持将drawable对象作为背景的所有组件都可以。其中各项属性的名称可谓见名知意,不再赘述。2.5 ClipDrawable资源:
ClipDrawable表示从其他位图(注意是位图)上clip(截取)的一个图片片段。 定义时的根元素是<clip.../>
。 总共可以指定三个属性:
android:drawable
: 指定截取的源位图文件;android:clipOrientation
: 指定截取方向,可以指定水平(horizontal)截取或者垂直(vertical)截取;android:gravity
: 指定截取时的对齐方式;可选的值为: top, bottom, left, right, center_vertical, fill_vertical, center_horizontal, fill_horizontal, center, fill, clip_vertical, clip_horizontal。 调用ClipDrawable对象的setLevel(int level)方法可以设置截取区域的大小。level的范围在[0,10000]。也就是说,当level=0时,一点都不截取;当level=10000时,截取整张图片。
举例: 比如我们可以借助ClipDrawable和Timer类打造一个简单的进度显示圆: 先定义 my_clip.xml
:
复制代码
再在ImageView中引用my_clip
:
复制代码
最后再java代码中进行设置:
public class MainActivity extends AppCompatActivity { ImageView showImage; Button bn; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); showImage = (ImageView) findViewById(R.id.show_image); bn = (Button) findViewById(R.id.bn_show_progress);//获取图片所显示的ClipDrawable对象 final ClipDrawable circle = (ClipDrawable) showImage.getDrawable(); final Handler handler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg);//如果消息是本程序发送的: if (msg.what == 0x123) { //修改ClipDrawable的level值 circle.setLevel(circle.getLevel() + 200); int currentLevel = circle.getLevel(); } } };//设置button的监听器 bn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) {//设置bn不可被点击 bn.setEnabled(false); final Timer timer = new Timer(); timer.schedule(new TimerTask() { @Override public void run() { Message msg = new Message(); msg.what = 0x123;//发送消息,通知应用修改ClipDrawable对象的level值 handler.sendMessage(msg);//取消定时器 if (circle.getLevel() >= 10000) timer.cancel(); } }, 0, 200); } }); }}复制代码
效果:
--以上:第二部分--3.1 ColorStateList资源
ColorStateList在好多书上都没提到,但是却是十分有用。 前面有提到StateListDrawable,它会根据不同的状态来引用不同的drawable对象。但是改变的往往是背景色,对于文字颜色就爱莫能助了。 比如,我们想要让一个button在被设置成enabled="false"
之后,背景色变为黑色,这很简单:
复制代码
并且我们定义一个StaleListDrawable命名为bn_state_list
,使引用它的按钮在不可使用时背景色变黑:
复制代码
接下来在java代码中设置bn_right的监听器,让它被按下时,bn_left的enabled的属性被设置为"false",也就是不可使用的状态。 此时,我们会发现,非常尴尬的一幕发生了:
当左边按钮的背景色变黑之后,它上面文字的颜色却没有随之改变,用户体验肯定会大打折扣。 这个时候ColorStateList就能派上用场了: 不同的是,这次我们不再在drawable文件夹上右击新建了,而是再创建一个color文件夹,并在里面新建名为button_text_color.xml
的文件:
复制代码
可以看到我们的根元素同样是和StateListDrawable一样的selector(选择器),并且我们为按钮的不同状态指定了不同的文字颜色。接下来只需要引用这个文件了:
复制代码
可以看到,background和textColor引用的是不同的文件。而使我们能随状态改变按钮文字颜色的正是android:textColor="@color/button_text_color"
。 效果:
看别人写总是很简单,自己总结一遍才发现: 在写代码的道路上,总有刁民想害朕。所以说,还是得亲“历”亲为啊。 篇幅有限,水平有限。文中如有纰漏,欢迎批评指正。 诸君共勉 : )