浅谈Android中Drawable使用知识总结

本文是学习《Android开发艺术探索》中Drawable章节之后的一个总结。

Drawable在我们平时的开发中,基本都会用到,而且给大家非常的有用。那么什么是Drawable呢?能够在canvas上绘制的一个玩意,而且相比于View,并不需要去考虑measure、layout,仅仅只要去考虑如何draw(canavs)。当然了,对于Drawable传统的用法,大家肯定不陌生 ,今天主要给大家带来以下几个Drawable的用法:

1、自定义Drawable,相比View来说,Drawable属于轻量级的、使用也很简单。以后自定义实现一个效果的时候,可以改变View first的思想,尝试下Drawable first。

2、自定义状态,相信大家对于State Drawable都不陌生,但是有没有尝试过去自定义一个状态呢?

3、利用Drawable提升我们的UI Perfermance , 如何利用Drawable去提升我们的UI的性能。

一、常见的Drawable种类介绍

Drawable类 xml标签 描述
BitmapDrawable <bitmap/> 表示一张图片,与直接引用原始图片相比可以设置一些效果
ShapeDrawable <shape/> 通过颜色构造各种形状的图形,标签对应的实体类实际是GradientDrawable
LayerDrawable <layer-list/> 表示一种层次化的Drawable集合,可以将不同的Drawable放置在不同的层上达到叠加效果
StateListDrawable <selector/> 表示一种Drawable集合,集合中每个Drawable对应着View的一种状态,最常用于Button
LevelListDrawable <level-list/> 表示一种Drawable集合,集合中每个Drawable(item)都有一个等级(level)的概念。可以根据不同的等级切换对应的Drawable。每个Drawable(item)对应一个等级范围,可以通过Drawable的setLevel方法来切换,如果用作ImageView的前景,还可以通过ImageView的setImageLevel方法来切换Drawable。level范围0-10000。
TransitionDrawable <transition/> 用于实现两个Drawable之间的淡入淡出效果,通过该Drawable中的startTransition和reverseTransition方法实现淡入淡出和逆过程,两个方法接收一个时间参数。
InsetDrawable <inset/> 可以将其他Drawable内嵌到自己当中,并且可以在四周流出一定的距离。当一个View希望背景比自己实际区域小的时候,可以用这个Drawable。LayerDrawable可以实现相同的效果
ScaleDrawable <scale/> 可以根据自己的等级将指定的Drawable缩放到一定的比例。
ClipDrawable <clip/> 根据自己当前的等级来裁剪另一个Drawable,裁剪方向可以通过android:clipOrientation和android:gravity两个属性共同控制。

二、各种Drawable的xml属性详解

1.<bitmap/>

<bitmap
 xmlns:android="http://schemas.android.com/apk/res/android"
 android:src="图片资源id"
 android:antialias="true|false"
 android:dither="true|false"
 android:filter="true|false"
 android:gravity="..."
 android:mipMap="true|false"
 android:tileMode="disabled|clamp|repeat|mirror" />

antialias抗锯齿,开启后会让图片变得平滑,同时也会在一定程度上降低图片的清晰度,但是降低的幅度低至可以忽略,所以应该开启;

dither抖动效果,当图片的像素配置与手机屏幕的像素配置不一致时,开启这个选项可以让高质量图片在低质量的屏幕上还能保持较好的显示效果,比如图片的色彩模式为ARGB8888,但是设备屏幕所支持的色彩模式为RGB555,这时候开启抖动选项可以让图片显示不会过于失真,在Android中创建Bitmap一般会选用ARGB8888这个模式,在这种色彩模式下一个像素所占的大小为4个字节,一个像素的位数总和越高,图像也就越逼真。根据分析,抖动效果应该开启;

filter过滤效果,当图片尺寸被拉伸或压缩时,过滤可以保持较好的显示效果,应该开启;

mipMap一种图像处理技术,不常用,默认false即可;

titleMode平铺模式。

点9图片对应NinePatchDrawable,xml标签是<nine-patch/>

2.<shape/>

<shape
 xmlns:android="http://schemas.android.com/apk/res/android"
 android:shape="rectangle|oval|line|ring">
 <corners
  android:radius="integer"
  android:topLeftRadius="integer"
  android:topRightRadius="integer"
  android:bottomLeftRadius="integer"
  android:bottomRightRadius="integer" />
 <gradient
  android:angle="integer"
  android:centerX="integer"
  android:centerY="integer"
  android:centerColor="color"
  android:endColor="color"
  android:gradientRadius="integer"
  android:startColor="color"
  android:type="linear|radial|sweep"
  android:useLevel="true|false" />
 <padding
  android:left="integer"
  android:top="integer"
  android:right="integer"
  android:bottom="integer" />
 <size
  android:width="integer"
  android:height="integer" />
 <solid
  android:color="color" />
 <stroke
  android:width="integer"
  android:color="color"
  android:dashWidth="integer"
  android:dashGap="integer" />
</shape>

android:shape图形形状,四个选项:rectangle(矩形)、oval(椭圆)、line(横线)、ring(圆环)。默认是矩形,line和ring必须通过<stroke>标签来指定线的宽度和颜色等信息,否则无法达到预期的显示效果。

针对ring这个形状,有5个特殊属性:

android:innerRadius 内环半径,与android:innerRadiusRatio同时存在时,以android:innerRadius为准
android:thickness 圆环厚度,即外半径减去内半径的大小,与android:thicknessRatio同时存在时以android:thickness为准
android:innerRadiusRatio 内半径占整个Drawable的宽度比例,默认值9。如果是n,那么内半径=宽度/n
android:thicknessRatio 厚度占整个Drawable的宽度比例,默认值3。如果是n,那么厚度=宽度/n
android:useLevel 一般都应该使用false,否则有可能无法达到预期效果,除非被当作LevelListDrawable来使用

<corners>

表示四个角的角度,只适用于shape,这里的角度指的是圆角的程度,用px来表示,5个属性:

  1. android:radius 四个角同时设定相同的角度,优先级较低,会被其他4个属性覆盖。
  2. android:topLeftRadius 左上角
  3. android:topRightRadius 右上角
  4. android:bottomLeftRadius 左下角
  5. android:bottomRightRadius 右下角

<gradient>

表示渐变色,与<solid>纯色标签互斥,属性如下:

  1. android:angle 渐变的角度,影响渐变方向,默认为0,值必须是45的倍数,比如0表示从左到右,90表示从上到下
  2. android:centerX 渐变中心点的横坐标
  3. android:centerY 渐变中心点的纵坐标,渐变的中心点影响渐变的具体效果
  4. android:startColor 渐变的起始色
  5. android:centerColor 渐变的中间色
  6. android:endColor 渐变的结束色
  7. android:gradientRadius 渐变半径,仅当type=radial时有效
  8. android:type 渐变类别,有三个值:linear(线性渐变)、radial(径向渐变)、sweep(扫描线渐变)。默认是线性渐变。
  9. android:useLevel 一般为false,当作为StateListDrawable使用时为true

<solid>

纯色填充,属性android:color表示填充颜色

<stroke>

Shape的描边,属性如下:

  1. android:width 描边的宽度,越大shape的边缘性看起来越粗
  2. android:color 描边的颜色
  3. android:dashWidth 组成虚线的线段的宽度
  4. android:dashGap 组成虚线的线段之间的间隔
  5. android:dashWidth和android:dashGap有一个为0,那么虚线效果不生效。

<padding>

表示包含它的View的空白,有上下左右四个属性。

<size>

shape的大小,但不是shape最终的大小因为shape一般会自适应View的宽高。

3.<layer-list/>

<layer-list
 xmlns:android="http://schemas.android.com/apk/res/android" >
 <item
  android:drawable=""
  android:id=""
  android:top=""
  android:right=""
  android:bottom=""
  android:left="" />
</layer-list>

一个layer-list可以包含多个item,每个item表示一个Drawable。

android:top android:right android:bottom android:left设置上下左右的偏移量。

android:drawable 直接引用一个Drawable资源,也可以在item中自定义Drawable。

默认情况layer-list中的所有Drawable都会被缩放至View的大小

4.<selector/>

<selector
 xmlns:android="http://schemas.android.com/apk/res/android"
 android:constantSize="true|false"
 android:dither="true|false"
 android:variablePadding="true|false"
 >
 <item
  android:drawable=""
  android:state_pressed="true|false"
  android:state_focused="true|false"
  android:state_hovered="true|false"
  android:state_selected="true|false"
  android:state_checkable="true|false"
  android:state_checked="true|false"
  android:state_enabled="true|false"
  android:state_activated="true|false"
  android:state_window_focused="true|false"
  />
</selector>

android:constantSize属性表示StateListDrawable的固有大小是否不随状态的改变而改变,因为状态的改变会导致切换到具体的Drawable,而不同状态的Drawable可能大小不同。true表示固有大小保持不变。dither表示抖动效果。android:variablePadding表示StateListDrawable的padding是否随状态的改变而改变,不建议开启。

<item>

每个item都表示一种状态下的Drawable信息。常见状态如下:

android:state_pressed 按下状态
android:state_focused 获取焦点
android:state_selected 用户选择了View
android:state_checked 用户选中了View,一般用于CheckBox这类在选中和非选中状态之间切换的View
android:state_enabled View处于可用状态

系统会根据View的状态从selector中选择对应的item,按照从上到下的顺序查找,直至查找到第一个匹配的item。一般默认的item都应该放在selector的最后一条并且不附带任何状态,这样当上面的item都无法匹配View的当前状态时,就会选择默认的item,因为默认的item不附带状态,所以它可以匹配View的任何状态。

5.<level-list/>

<level-list
 xmlns:android="http://schemas.android.com/apk/res/android" >
 <item
  android:drawable=""
  android:minLevel=""
  android:maxLevel="" />
</level-list>

示例代码

<?xml version="1.0" encoding="utf-8"?>
<level-list xmlns:android="http://schemas.android.com/apk/res/android" >
 <item android:drawable="@drawable/s1" android:minLevel="0" android:maxLevel="20"/>
 <item android:drawable="@drawable/s2" android:minLevel="21" android:maxLevel="40"/>
 <item android:drawable="@drawable/s3" android:minLevel="41" android:maxLevel="60"/>
 <item android:drawable="@drawable/s4" android:minLevel="61" android:maxLevel="100"/>
</level-list>
//id是level_list_img的ImageView用上面的level-list做背景
ImageView iv = (ImageView) findViewById(R.id.level_list_img);
LevelListDrawable levelListDrawable = (LevelListDrawable) iv.getDrawable();
int level = ???; //业务逻辑得出一个level信息,比如当前电量
levelListDrawable.setLevel(level); //根据得出的电量level信息显示level-list中的相应电量的图片

6.<transition/>

<transition xmlns:android="http://schemas.android.com/apk/res/android" >
 <item
  android:drawable=""
  android:id=""
  android:left=""
  android:top=""
  android:right=""
  android:bottom="" />
</transition>

两个Drawable之间的淡入淡出效果,属性同前面的Drawable,示例代码:

<?xml version="1.0" encoding="utf-8"?>
<transition xmlns:android="http://schemas.android.com/apk/res/android" >
 <item android:drawable="@drawable/drawable1"/>
 <item android:drawable="@drawable/drawable2"/>
</transition>
//id是text_view的TextView用上面的transition做背景
TextView tv = (TextView) findViewById(R.id.text_view);
TransitionDrawable drawable = (TransitionDrawable) tv.getDrawable();

drawable.startTransition(1000);
//drawable.reverseTransition(1000);//逆过程

7.<inset/>

<inset xmlns:android="http://schemas.android.com/apk/res/android"
 android:drawable=""
 android:insetLeft=""
 android:insetTop=""
 android:insetRight=""
 android:insetBottom="" />

将其他drawable内嵌到inset中,并且可以在四周留出一定的间距,属性和前面的Drawable类似。下面的示例代码实现了inset中的shape距离View的边界为15dp,layer-list可以实现相同效果:

<?xml version="1.0" encoding="utf-8"?>
<inset xmlns:android="http://schemas.android.com/apk/res/android"
 android:insetBottom="15dp"
 android:insetLeft="15dp"
 android:insetRight="15dp"
 android:insetTop="15dp">

 <shape android:shape="rectangle">
  <solid android:color="#ff0000"/>
 </shape>

</inset>

8.<scale/>

<scale xmlns:android="http://schemas.android.com/apk/res/android"
 android:drawable=""
 android:scaleGravity=""
 android:scaleHeight=""
 android:scaleWidth="" />

android:scaleGravity等同于shape中的android:gravity,android:scaleWidth和android:scaleHeight分别表示对指定drawable宽和高的缩放比例,以百分比的形式表示(看下面的示例代码)。使用scale的时候需要考虑ScaleDrawable的level值,levle是0的时候表示ScaleDrawable不可见,0也是默认值,所以要想ScaleDrawable可见,level等级不能是0。示例代码如下:

<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
 android:drawable="@drawable/test_drawable"
 android:scaleGravity="center"
 android:scaleHeight="70%"
 android:scaleWidth="70%" />
View view = findViewById(R.id.test_view);
ScaleDrawable drawable = (ScaleDrawable)view.getBackground();
drawable.setLevel(1);

代码中必须设置level值,否则默认值0是不可见的。level范围系统内部约定为0-10000,当然设置成20000也能正常工作但不推荐那样做。

9.<clip/>

<clip xmlns:android="http://schemas.android.com/apk/res/android"
 android:drawable=""
 android:clipOrientation=""
 android:gravity="" />

clipOrientation表示裁剪方向,有水平和竖直两个方向。gravity和clipOrientation一起才能发挥作用,gravity的值如下:

含义
top 将内部Drawable放在容器顶部,不改变它的大小。如果竖直裁剪,那么从底部开始裁剪
bottom 将内部Drawable放在容器底部,不改变它的大小。如果竖直裁剪,那么从顶部开始裁剪
left 将内部Drawable放在容器左边,不改变它的大小。如果水平裁剪,那么从右边开始裁剪
这是默认值
right 将内部Drawable放在容器右边,不改变它的大小,如果水平裁剪,那么从左边开始裁剪
center_vertical 将内部Drawable在容器中竖直居中,不改变大小,如果竖直裁剪,那么从上下同时开始裁剪
fill_vertical 将内部Drawable竖直方向填充容器。如果为竖直裁剪,那么仅当ClipDrawable的等级为0时(0表示ClipDrawable被完全裁剪,即不可见),才能有裁剪行为
center_horizontal 类似center_vertical,方向不同
fill_horizontal 类似fill_vertical,方向不同
center 将内部Drawable水平和竖直方向都居中,不改变大小。如果竖直裁剪,那么从上下同时裁剪,如果水平裁剪,那么从左右同时裁剪
fill 将内部Drawable水平和竖直方向同时填充,仅当ClipDrawable的等级为0时,才有裁剪行为
clip_vertical 附加选项,表示竖直方向裁剪,较少使用
clip_horizontal 附加选项,表示水平方向裁剪,较少使用

Drawable等级是有范围的,即0-10000,最小值0表示完全裁剪,即整个Drawable都不可见。最大值10000表示不裁剪。如果竖直方向从上向下裁剪,level值是8000表示裁剪了2000,即在顶部裁剪掉20%的区域,被裁剪的区域就相当于不存在了。

三、Drawable的 level 总结

上面xml属性介绍中有些drawable中level是很重要的,这里总结一下:

  1. <level-list/> 中有多个item,每个item对应一个drawable,通过设置具体的level值来决定使用哪个item即drawable。
  2. <scale/> 用于缩放,level默认值是0,0表示ScaleDrawable不可见,所以要想ScaleDrawable可见,必须设置level不为0,具体是几无所谓,不为0即可。
  3. <clip/> 表示裁剪,level值决定裁剪百分比,需要具体值,因为决定裁剪百分比。

level值的范围系统规定0-10000,设置level值的方法:

  1. 将相应的Drawable设置成一个View的背景
  2. 从View的背景中取得相应Drawable对象,代码view.getDrawable() 或 view.getBackground(),强转成相应的Drawable类型即可
  3. 取得Drawable对象后调用setLevel()方法设置level。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • 关于Android中drawable必知的一些规则

    前言 一入 Android 深似海,相信很多 Android 开发者深有体会,Android 系统版本的碎片化,Android 硬件设备的多样性,第三方 Rom 的不确定因素.现在想开发一个合格的商业化 App 真的不容易,先不说别的,应用的兼容性就是一项技术和耐心的双重考验,想完美适配各种情况可以说是不可能的,往往都是在人力和适配率之间寻找平衡,今天要说的 drawable 就是需要适配的一个重要角色. 配置限定符 对于不同的屏幕密度.不同的设备方向,不同的语言和区域,都会涉及到备选 draw

  • 详解Android中Drawable方法

    本文为大家分享了Android中Drawable方法的详细使用方法,供大家参考,具体内容如下 1. BitmapDrawable相关方法: 新建在drawable目录下面,示例如下: <bitmap xmlns:android="http://schemas.android.com/apk/res/android" android:antialias="true" android:dither="true" android:filter=&

  • android中图形图像处理之drawable用法分析

    本文实例讲述了android中图形图像处理之drawable用法.分享给大家供大家参考.具体如下: 一.如何获取 res 中的资源 数据包package:android.content.res 主要类:Resources 其主要接口按照功能,划分为以下三部分: getXXXX() 例如: int getColor(int id) Drawable getDrawable(int id) String getString(int id)  直接获取res中存放的资源 InputStream ope

  • 浅谈Android中Drawable使用知识总结

    本文是学习<Android开发艺术探索>中Drawable章节之后的一个总结. Drawable在我们平时的开发中,基本都会用到,而且给大家非常的有用.那么什么是Drawable呢?能够在canvas上绘制的一个玩意,而且相比于View,并不需要去考虑measure.layout,仅仅只要去考虑如何draw(canavs).当然了,对于Drawable传统的用法,大家肯定不陌生 ,今天主要给大家带来以下几个Drawable的用法: 1.自定义Drawable,相比View来说,Drawable

  • 浅谈Android中Service的注册方式及使用

    Service通常总是称之为"后台服务",其中"后台"一词是相对于前台而言的,具体是指其本身的运行并不依赖于用户可视的UI界面,因此,从实际业务需求上来理解,Service的适用场景应该具备以下条件: 1.并不依赖于用户可视的UI界面(当然,这一条其实也不是绝对的,如前台Service就是与Notification界面结合使用的): 2.具有较长时间的运行特性. 1.Service AndroidManifest.xml 声明 一般而言,从Service的启动方式上

  • 浅谈android中数据库的拷贝

    SQLiteDatabase不支持直接从assets读取文件,所以要提前拷贝数据库.在读取数据库时,先在项目中建立assets文件夹用于存放外部文件,将数据库文件拷到该目录下. 代码方法: /** * 拷贝数据库至file文件夹下 * @param dbName 数据库名称 */ private void initAddressDB(String dbName) { //1,在files文件夹下创建同名dbName数据库文件过程 File files=getFilesDir();//获取/dat

  • 浅谈Android中适配器的notifyDataSetChanged()为何有时不刷新

    学过Android开发的人都知道,ListView控件在开发中经常遇到,并且ListView通常结合Adapter适配器来进行数据显示和数据更新操作.姑且假设数据存储在名为dataList的成员变量中.数据操作无非是增加数据.删除数据这两种主要的操作,而当数据有所变化时,为了及时向用户提供更新后的数据,我们知道需要在数据更新后调用适配器的notifyDataSetChanged()方法,来显示更新后的数据.殊不知,该方法并非百试不爽,在此我们便来讨论下具体的原因,其实本质是关注内存的分配情况.

  • 浅谈Android中AsyncTask的工作原理

    概述 实际上,AsyncTask内部是封装了Thread和Handler.虽然AsyncTask很方便的执行后台任务,以及在主线程上更新UI,但是,AsyncTask并不合适进行特别耗时的后台操作,对于特别耗时的任务,个人还是建议使用线程池.好了,话不多说了,我们先看看AsyncTask的简单用法吧. AsyncTask使用方法 AsyncTask是一个抽象的泛型类.简单的介绍一下它的使用方式代码如下: package com.example.huangjialin.myapplication;

  • 浅谈Android中关于静态变量(static)的使用问题

    项目中,在不停地接收串口数据很长一段时间(几小时)后,会偶然性的报错.初步排除了oom和cpu紧张问题,因为是工业平板不方便调试,用了些比较笨的方法最后锁定在几个用了static的地方.在这里记录下Android中使用static的一些问题. 静态变量的生命周期遵守Java的设计.静态变量在类被load的时候分配内存,并存在于方法区.当类被卸载时,静态变量被销毁.在PC机的客户端程序中,一个类被加载和卸载,可简单的等同于jvm进程的启动和结束.在Android中,用的DVM也是一样的,不过And

  • 浅谈Android中多线程切换的几种方法

    我们知道,多线程是Android开发中必现的场景,很多原生API和开源项目都有多线程的内容,这里简单总结和探讨一下常见的多线程切换方式. 我们先回顾一下Java多线程的几个基础内容,然后再分析总结一些经典代码中对于线程切换的实现方式. 几点基础 多线程切换,大概可以切分为这样几个内容:如何开启多个线程,如何定义每个线程的任务,如何在线程之间互相通信. Thread Thread可以解决开启多个线程的问题. Thread是Java中实现多线程的线程类,每个Thread对象都可以启动一个新的线程,注

  • 浅谈Android中视图动画的属性与使用

    简介 Android动画主要包括视图动画和属性动画,视图动画包括Tween动画和Frame动画,Tween动画又包括渐变动画.平移动画.缩放动画.旋转动画. Tween动画的基本属性 目标 View: 时常 duration; 开始状态 fromXXX; 结束动画 toXXX; 开始时间 startOffset; 重复次数 repeatCount; 时间轴 interpolator(插值器). 代码示例 xml实现 <?xml version="1.0" encoding=&qu

  • 浅谈Android 中图片的三级缓存策略

    什么是三级缓存? 内存缓存,优先加载,速度最快 本地缓存,次优先加载,速度快 网络缓存,最后加载,速度慢,浪费流量 为什么要进行三级缓存 三级缓存策略,最实在的意义就是 减少不必要的流量消耗,增加加载速度 . 如今的 APP 网络交互似乎已经必不可少,通过网络获取图片再正常不过了.但是,每次启动应用都要从网络获取图片,或者是想重复浏览一些图片的时候,每次浏览都需要网络获取,消耗的流量就多了,在如今的流量资费来说,肯定会容易影响用户数量. 还有就是网络加载图片,有时候会加载很慢,影响了用户体验.

  • 浅谈Android中使用异步线程更新UI视图的几种方法

    在Android中子线程是不能更新ui的. 所以我们要通过其他方式来动态改变ui视图, 1.runOnUiThread activity提供的一个轻量级更新ui的方法,在Fragment需要使用的时候要用getActivity.runOnUiThread开启线程 这种方法最简单,方便更新一些不需要判断的通知,比如在聊天项目中动态获取未读消息数量. runOnUiThread(new Runnable() { @Override public void run() { sendMessage("[

随机推荐