Android 中图片和常见的颜色都可以是一个Drawable. Drawable可以方便我们做出一些特殊的UI效果,这一点在UI相关的开发工作中尤其重要。其主要优点有:

  • 使用简单,比自定义View成本要低;
  • 非图片类型的Drawable占用空间小,对减小apk大小有帮助;

Drawable作为图片的时,内部的宽/高这个参数比较重要,通过getIntrinsicWidth和getIntrinsicHeight这两个方法获得。但作为颜色背景时,是没有宽高概念的,会自动延伸和View的背景大小一样。

Drawable的分类:常见的有BitmapDrawable、ShapeDrawable、LayerDrawable以及StateListDrawable等。

1.BitmapDrawable: 表示一张图片,可以直接引用原图片,或者用XML文件来进行描述。一般直接引用原图片。

2.ShapeDrawabe:  是一种常见的通过颜色来构造的图形,可以是纯色图形,也可以是渐变的图形。这种情况下,用<shape>标签来创建drawable。简单介绍一下它的主要参数:

<?xml version="1.0" encoding="utf-8"?>
<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="integer"
android:type=["linear" | "radial" | "sweep"]
android:useLevel="true" /> <padding android:left="integer"
android:right="integer"
android:top="integer"
android:bottom="integer" /> <size android:width="integer"
android:height="integer" /> <solid android:color="color" /> <stroke android:color="color"
android:width="integer"
android:dashWidth="integer"
android:dashGap="integer" />
</shape>
shape            

1.  rectangle 矩形

2.  oval 椭圆

3.  line 横线

4.  ring 圆环

corners

1.  圆角半径

2.  radius的优先级比后面的topLeftRadius,topRightRadius等要低;

gradient

和<solid>标签是互斥的,因为solid表示纯色填充。
angle:渐变的角度,0表示从左到右,90表示从上到下
centerX:渐变中心的横坐标
centerY:渐变中心的纵坐标
centerColor:渐变中心的颜色
endColor:渐变的结束色
gradientRadius:渐变半径
startColor:渐变的起始色
centerColor:渐变的中间色
type=["linear" | "radial" | "sweep"]渐变类型:线性渐变,辐射渐变,扫描渐变;默认为线性渐变
useLevel:一般为false,当drawable为stateListDrawable使用时为true

 padding  表示的不是shape的空白,而是View的空白
 size  设置为shapeDrawable的宽高,但是如果当做背景时,仍然是根据view的大小进行拉伸;
 solid  表示纯色填充
 stroke

Shape的描边:

wide:描边宽度

color:描边颜色

dashWidth: 虚线描边宽度

dashGap: 虚线的间隔

3.LayerDrawable: 对应的是<layer-list>标签开头。是一种层级化的Drawable集合。<item>中可以自定义drawable,也可以引用定义好的drawable资源.

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/ic_launcher_background"
android:id="@+id/xxx"
android:top="integer"
android:bottom="integer"
android:left="integer"
android:right="integer" />
</layer-list>

top,bottom,left, right分别表示相对于View的上下左右偏移量。

下面的Item会覆盖上面的item。在自定义进度条的时候可以用到LayerDrawable。

比如做一个简单的文本输入框的背景:

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="rectangle">
<solid android:color="#0ac39e" />
</shape>
</item> <item android:bottom="6dp">
<shape android:shape="rectangle">
<solid android:color="#fff"/>
</shape>
</item> <item android:bottom="1dp"
android:left="1dp"
android:right="1dp">
<shape android:shape="rectangle">
<solid android:color="#fff" />
</shape>
</item> </layer-list>

在布局文件中给EditTextView设置自定义的文本输入框背景,就有了如下效果:

 <EditText
android:layout_width="300dp"
android:layout_height="wrap_content"
android:text="文本框"
android:background="@drawable/text_imput_drawable"/>

4.StateListDrawable: 对应<selector>标签,也是一种drawable集合,对应view的状态显示相应的drawable背景。

View的常见状态
android:state_pressed 表示按下状态,按下没有松开的状态
android:state_focused 表示View已经获得焦点
android:state_selected 表示用户选择了View
android:state_checked 表示用户选中了View,如CheckBox
android:state_enabled 表示View当前可用

一般来说,会从上到下进行selector的匹配,在最后应该设置一个默认的状态,就是不附带任何信息的状态。当item都无法匹配的时候,会选择这个默认状态。

5.LevelListDrawable: 对应<level-list>标签,同样表示一个Drawable集合,不过有等级,会根据不同的等级进行切换。minLevel和maxLevel,等级的范围为0~10000。当作为View的背景时,可以通过Drawable的setLevel方法来设置不同等级从而切换具体的Drawable。如果作为ImageView的前景Drawable,还可以通过ImageView的setImageLevel方法来切换Drawable。

6.TransitionDrawable: 对应<transition>标签,用于实现两个Drawable之间的淡入淡出的效果。

<?xml version="1.0" encoding="utf-8"?>
<transition xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@[package:]drawable/drawable_resource"
android:id="@[+][package:]id/resource_name"
android:top="dimension"
android:left="dimension"
android:right="dimension"
android:bottom="dimension" />
</transition>

例子:

定义一个TransitionDrawable,如下图所示:

<?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>

接着将上面的TransitionDrawable设置为View的背景,也可以在ImageView中直接作为Drawable来使用。

TextView view = findViewById(R.id.tv);
TransitionDrawable drawable = (TransitionDrawable) view.getBackground();
drawable.startTransition(1000);

通过startTransition和reverseTransition方法来实现淡入淡出的效果以及它的逆过程。

7.InsetDrawable: 对应<inset>标签,它可以将其它的Drawable内嵌到自己当中,并可以四周留出一定的间距。当一个View希望自己的背景比自己的实际区域小的时候,可以采用InsetDrawable来实现。

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

一个简单的应用:

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

8.ScaleDrawable: 对应<scale>标签,它可以根据自己的等级level将指定的Drawable缩放到一定比例,默认等级为0,不显示,所以需要设置等级这一步,等级范围0~10000。

eg.

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

9.ClipDrawable: 对应<clip>标签,它可以根据自己的等级level来裁剪另一个Drawable,裁剪方向可以根据android:clipOrientation和android:gravity这两个属性来共同控制。对于ClipDrawable来说,等级0表示完全裁剪,等级10000表示不裁剪。等级设置为8000表示裁剪了2000,裁剪20%。等级越大,表示裁剪的区域越小。

10.自定义Drawable:Drawabe的使用很单一,一种是作为ImageView中的图片来显示,一种是作为View的背景。大多数情况都是以View的背景的形式出现。

Drawable的原理比很简单,是通过调用draw方法来绘制背景。例如自定义Drawable的原形背景。

/**
* 圆形颜色背景绘制
*/
public class CircleDrawable extends Drawable{
private Paint mPaint; public CircleDrawable(int color){
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setColor(color);
} @Override
public void draw(@NonNull Canvas canvas) {
final Rect rect = getBounds();
float cx = rect.exactCenterX();
float cy = rect.exactCenterX();
canvas.drawCircle(cx, cy, Math.min(cx, cy), mPaint);
} @Override
public void setAlpha(int alpha) {
mPaint.setAlpha(alpha);
} @Override
public void setColorFilter(@Nullable ColorFilter colorFilter) {
mPaint.setColorFilter(colorFilter);
} @Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
}
}
/**
* 圆角矩形图片背景
*/
public class RoundImageDrawable extends Drawable {
private Paint mPaint;
private Bitmap mBitmap;
private RectF mRectF; public RoundImageDrawable(Bitmap bitmap){
this.mBitmap = bitmap;
BitmapShader bitmapShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setShader(bitmapShader);
} @Override
public void setBounds(@NonNull Rect bounds) {
super.setBounds(bounds);
mRectF = new RectF(bounds.left, bounds.top, bounds.right, bounds.bottom);
} @Override
public void draw(@NonNull Canvas canvas) {
canvas.drawRoundRect(mRectF, 20, 20, mPaint);
} @Override
public int getIntrinsicHeight() {
return mBitmap.getHeight();
} @Override
public int getIntrinsicWidth() {
return mBitmap.getWidth();
} @Override
public void setAlpha(int alpha) {
mPaint.setAlpha(alpha);
} @Override
public void setColorFilter(@Nullable ColorFilter colorFilter) {
mPaint.setColorFilter(colorFilter);
} @Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT; //设置透明
}
}

自定义Drawable中,draw, setAlpha,setColorFilter和getOpacity这几个方法必须实现,draw方法最主要,这个方法和View的draw方法类似。当drawable有固定大小的时候最好重写getIntrinsicWidth和getIntrinsicHeight方法,因为它会影响到View的wrap_content布局。如果是颜色填充,没有大小概念,此时返回-1。drawable实际大小可以通过getBounds方法得到,一般和View的大小一样。

Android之Drawable的更多相关文章

  1. Android使用Drawable资源之使用ClipDrawable资源 实现进入条

    以前我自定义的进度条(就是咱们现在工程中用的)是从android的源码中扒出来的一个XML,然后把里面的图片给替换了.一直不知道它的具体原理是什么. 今天得空研究了一下,发现它的原理其实就是用的and ...

  2. Android之drawable state各个属性详解

    android:drawable 放一个drawable资源android:state_pressed 是否按下,如一个按钮触摸或者点击.android:state_focused 是否取得焦点,比如 ...

  3. Android Studio中使用android:src="@drawable/ic_launcher"报错

    今天尝试着安装了Android Studio,界面确实不错,列表什么的也改了很多. 然后新建工程,习惯性在activity_main那里加上一段代码测试看看: <ImageView androi ...

  4. Android动画Drawable Animation

    Drawable Animation是逐帧动画,那么使用它之前必须先定义好各个帧.我们可以通过代码定义,也可以使用xml文件定义,一般使用后者.如下: <?xml version="1 ...

  5. Android 自定义Drawable

    1.使用BitmapShader实现图片圆角 public class CornerDrawable extends Drawable { private Paint mPaint; private ...

  6. Android的Drawable缓存机制源码分析

    Android获取Drawable的方式一般是Resources.getDrawable(int),Framework会返回给你一个顶层抽象的Drawable对象.而在Framework中,系统使用了 ...

  7. Android 自带图标库 android.R.drawable

    在xml文件中调用. android:title="@string/secure_connect"android:orderInCategory="100"an ...

  8. 玩转Android之Drawable的使用

    Drawable天天用,可你是否对Drawable家族有一个完整的认知?今天我们就来系统的学习一下Drawable的使用. 1.概述 用过Drawable的筒子都知道Drawable有很多种,有的时候 ...

  9. 《Android开发艺术探索》读书笔记 (6) 第6章 Android的Drawable

    本节和<Android群英传>中的第六章Android绘图机制与处理技巧有关系,建议先阅读该章的总结 第6章 Android的Drawable 6.1 Drawable简介 (1)Andr ...

  10. Android的Drawable

    1.获取Drawable的内部宽\高:getIntrinsicHeight/Width.但是并不是所有Drawable都有内部宽高(比如说一个颜色形成的宽高,Drawable的宽高不等于大小,大小是根 ...

随机推荐

  1. 漫谈android系统(4)bring up panel

    点击打开链接 版权声明: 作者:alex wang 版权:本文版权归作者和CSDN共有 转载:欢迎转载,为了保存作者的创作热情,请按要求[转载],谢谢 要求:未经作者同意,必须保留此段声明:必须在文章 ...

  2. Dom4j修改xml文档引入

    前面介绍了如何解析xnl文档的内容,这里对修改xml展开讨论. 一.首先看一下,写出内容到xml文档的主要代码: XMLWriter writer = new XMLWriter(OutputStre ...

  3. 关于React Native 火热的话题,从入门到原理

    本文授权转载,作者:bestswifter(简书) React Native 是最近非常火的一个话题,介绍如何利用 React Native 进行开发的文章和书籍多如牛毛,但面向入门水平并介绍它工作原 ...

  4. Linux Debugging(五): coredump 分析入门

    作为工作几年的老程序猿,肯定会遇到coredump,log severity设置的比较高,导致可用的log无法分析问题所在. 更悲剧的是,这个问题不好复现!所以现在你手头唯一的线索就是这个程序的尸体: ...

  5. oracle中去重复记录 不用distinct

    用distinct关键字只能过滤查询字段中所有记录相同的(记录集相同),而如果要指定一个字段却没有效果,另外distinct关键字会排序,效率很低 . select distinct name fro ...

  6. Java之谜 —— 来自Neal Gafter的演讲

    翻译人员: 铁锚 翻译日期: 2013年11月20日 原文链接: A Puzzle from "A Brief History of the (Java) World and a Peek ...

  7. js中return false,return,return true的用法及区别

    首先return作为返回关键字,他有以下两种返回方式 1.返回控制与函数结果 语法为:return 表达式; 语句结束函数执行,返回调用函数,而且把表达式的值作为函数的结果 2.返回控制无函数结果 语 ...

  8. 小强的HTML5移动开发之路(3)——HTML5与HTML4比较

    来自:http://blog.csdn.net/dawanganban/article/details/17652873 在前面介绍了HTML5的新特性,新标签的使用,智能表单设计,引入多媒体对象,C ...

  9. javascript概要学习

    Javascript是一种由Netscape的LiveScript发展而来的原型化继承的面向对象的动态类型的区分大小写的客户端脚本语言,主要目的是为了解决服务器端语言,比如Perl,遗留的速度问题,为 ...

  10. 【一天一道LeetCode】#10. Regular Expression Matching

    一天一道LeetCode系列 (一)题目 Implement regular expression matching with support for '.' and '*'. '.' Matches ...