1.Drawable简介

Android系统中将可绘制对象被抽象为Drawable,不同的绘制资源对应着不同的Drawable类型。Android FrameWork提供了常用的Drawable,Android控件的绘制资源基本都是通过Drawable形式实现的。一般情况下,开发者是不会直接接触Drawable的具体实现的,Drawable资源一般都放在res/drawable目录下,用户通过图片,xml格式的Drawable资源来使用。

Android内置的比较常用的Drawable类型包括:ColorDrawable、GradientDrawable、ShapeDrawable、BitmapDrawable、 NinePatchDrawable、InsetDrawable、ClipDrawable、ScaleDrawable、RotateDrawable、AnimationDrawable、LayerDrawable、LevelListDrawable、StateListDrawable、TransitionDrawable。

2.Drawable 特性

Drawable 比 View 更轻量级,它只是 View 绘制中过程被调用的一个东西(背景,前景)。

自定义 View 的时候,如果只要改变背景的话,最好不要去重写 draw 函数,Drawable 这个类已经被抽象出来负责背景的绘制了。

Drawable 有许许多多的子类,但最复杂的还是 Drawable 本身,作为父类的它要考虑到方方面面。

1).setBounds

最基本的形状是什么,是矩形。

无论 Drawable 最终呈现在画布上是什么形状的,它总是被限定在一个矩形当中。void setBackgroundBounds() {

if (mBackgroundSizeChanged && mBackground != null) {

mBackground.setBounds(0, 0, mRight - mLeft, mBottom - mTop);

mBackgroundSizeChanged = false;

rebuildOutline();

}

}

在绘制背景时,会将 View 的坐标转换为 bounds,所以 Drawable 都会被拉伸至 View 的大小。canvas.drawRect(getBounds(), mPaint);

2).setCallBackpublic static interface Callback {

public void invalidateDrawable(Drawable who);

public void scheduleDrawable(Drawable who, Runnable what, long when);

public void unscheduleDrawable(Drawable who, Runnable what);

}

View 在设置背景时,drawable 会把 callback 指向 View。background.setCallback(this);

Drawable 在需要重绘时,会调用:public void invalidateSelf() {

final Callback callback = getCallback();

if (callback != null) {

callback.invalidateDrawable(this);

}

}@Override

public void invalidateDrawable(@NonNull Drawable drawable) {

if (verifyDrawable(drawable)) {

final Rect dirty = drawable.getDirtyBounds();

final int scrollX = mScrollX;

final int scrollY = mScrollY;

invalidate(dirty.left + scrollX, dirty.top + scrollY,

dirty.right + scrollX, dirty.bottom + scrollY);

rebuildOutline();

}

}

这一步说明了,Drawable 是 View 附属,它不会仅仅重画自己。

scheduleSelf 是定时重绘自己的意思,就是动画的意思。

unscheduleSelf 则是取消上一步动画的意思,很多时候我们需要让动画戛然而止。

3).setState

View 有很多 State,比较常见的是 EditText 的 foucs,以及 Button 的 press。

Drawable 是否根据 View 的状态改变而做出相应的变化,就被称为 isStateful。

触发过程如下:

view.refreshDrawableState -> view.drawableStateChanged -> bg.setState -> bg.onStateChanged

3.Drawable的定义形式

一般情况下,除了图片资源是直接放在res/drawable下(android studio中图片放在res/minmap下),其他的Drawable都是以xml格式实现的,开发者通过在xml中使用shape,selector,level-list等标签来实现对应的Drawable,从而实现相应的可绘制资源的定义,最终view通过绘制这些Drawable来实现我们想要的显示效果。

Drawable中xml标签与Drawable对象的对应关系如以下表格所示:xml标签Drawable对象StateListDrawable

LevelListDrawable

LayerDrawable

TransitionDrawable

ColorDrawable

GradientDrawable

ScaleDrawable

ClipDrawable

RotateDrawable

AnimationDrawable

InsetDrawable

BitmapDrawable

NinePatchDrawable

4.从源码探索Drawable的加载过程

下面我们通过Framework的源代码来探索一下Drawable的加载过程,一般情况下,我们通过getResources().getDrawable(int id);的方式去加载。顺着这条线往下看,getDrawable->loadDrawable->loadDrawableForCookie->Drawable.createFromXml->createFromXmlInner,来看androidgraphicsdrawableDrawable.java的createFromXmlInner函数的实现代码。public static Drawable createFromXmlInner(Resources r, XmlPullParser parser, AttributeSet attrs,

Theme theme) throws XmlPullParserException, IOException {

final Drawable drawable;

final String name = parser.getName();

if (name.equals("selector")) {

drawable = new StateListDrawable();

} else if (name.equals("animated-selector")) {

drawable = new AnimatedStateListDrawable();

} else if (name.equals("level-list")) {

drawable = new LevelListDrawable();

} else if (name.equals("layer-list")) {

drawable = new LayerDrawable();

} else if (name.equals("transition")) {

drawable = new TransitionDrawable();

} else if (name.equals("ripple")) {

drawable = new RippleDrawable();

} else if (name.equals("color")) {

drawable = new ColorDrawable();

} else if (name.equals("shape")) {

drawable = new GradientDrawable();

} else if (name.equals("vector")) {

drawable = new VectorDrawable();

} else if (name.equals("animated-vector")) {

drawable = new AnimatedVectorDrawable();

} else if (name.equals("scale")) {

drawable = new ScaleDrawable();

} else if (name.equals("clip")) {

drawable = new ClipDrawable();

} else if (name.equals("rotate")) {

drawable = new RotateDrawable();

} else if (name.equals("animated-rotate")) {

drawable = new AnimatedRotateDrawable();

} else if (name.equals("animation-list")) {

drawable = new AnimationDrawable();

} else if (name.equals("inset")) {

drawable = new InsetDrawable();

} else if (name.equals("bitmap")) {

//noinspection deprecation

drawable = new BitmapDrawable(r);

if (r != null) {

((BitmapDrawable) drawable).setTargetDensity(r.getDisplayMetrics());

}

} else if (name.equals("nine-patch")) {

drawable = new NinePatchDrawable();

if (r != null) {

((NinePatchDrawable) drawable).setTargetDensity(r.getDisplayMetrics());

}

} else {

throw new XmlPullParserException(parser.getPositionDescription() +

": invalid drawable tag " + name);

}

drawable.inflate(r, parser, attrs, theme);

return drawable;

}

上面的对应关系就从这里来的,现在是不是一下子明朗了呢。在函数结尾,Drawable通过条用inflate函数解析AttributeSet中的属性信息,并设置Drawable相应的属性。看一下BitmapDrawable吧,public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme)

throws XmlPullParserException, IOException {

super.inflate(r, parser, attrs, theme);

final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.BitmapDrawable);

updateStateFromTypedArray(a);

verifyState(a);

a.recycle();

}

继续看updateStateFromTypedArrayprivate void updateStateFromTypedArray(TypedArray a) throws XmlPullParserException {

final Resources r = a.getResources();

final BitmapState state = mBitmapState;

// Account for any configuration changes.

state.mChangingConfigurations |= a.getChangingConfigurations();

// Extract the theme attributes, if any.

state.mThemeAttrs = a.extractThemeAttrs();

final int srcResId = a.getResourceId(R.styleable.BitmapDrawable_src, 0);

if (srcResId != 0) {

final Bitmap bitmap = BitmapFactory.decodeResource(r, srcResId);

if (bitmap == null) {

throw new XmlPullParserException(a.getPositionDescription() +

": requires a valid src attribute");

}

state.mBitmap = bitmap;

}

state.mTargetDensity = r.getDisplayMetrics().densityDpi;

final boolean defMipMap = state.mBitmap != null ? state.mBitmap.hasMipMap() : false;

setMipMap(a.getBoolean(R.styleable.BitmapDrawable_mipMap, defMipMap));

state.mAutoMirrored = a.getBoolean(

R.styleable.BitmapDrawable_autoMirrored, state.mAutoMirrored);

state.mBaseAlpha = a.getFloat(R.styleable.BitmapDrawable_alpha, state.mBaseAlpha);

final int tintMode = a.getInt(R.styleable.BitmapDrawable_tintMode, -1);

if (tintMode != -1) {

state.mTintMode = Drawable.parseTintMode(tintMode, Mode.SRC_IN);

}

final ColorStateList tint = a.getColorStateList(R.styleable.BitmapDrawable_tint);

if (tint != null) {

state.mTint = tint;

}

final Paint paint = mBitmapState.mPaint;

paint.setAntiAlias(a.getBoolean(

R.styleable.BitmapDrawable_antialias, paint.isAntiAlias()));

paint.setFilterBitmap(a.getBoolean(

R.styleable.BitmapDrawable_filter, paint.isFilterBitmap()));

paint.setDither(a.getBoolean(R.styleable.BitmapDrawable_dither, paint.isDither()));

setGravity(a.getInt(R.styleable.BitmapDrawable_gravity, state.mGravity));

final int tileMode = a.getInt(R.styleable.BitmapDrawable_tileMode, TILE_MODE_UNDEFINED);

if (tileMode != TILE_MODE_UNDEFINED) {

final Shader.TileMode mode = parseTileMode(tileMode);

setTileModeXY(mode, mode);

}

final int tileModeX = a.getInt(R.styleable.BitmapDrawable_tileModeX, TILE_MODE_UNDEFINED);

if (tileModeX != TILE_MODE_UNDEFINED) {

setTileModeX(parseTileMode(tileModeX));

}

final int tileModeY = a.getInt(R.styleable.BitmapDrawable_tileModeY, TILE_MODE_UNDEFINED);

if (tileModeY != TILE_MODE_UNDEFINED) {

setTileModeY(parseTileMode(tileModeY));

}

// Update local properties.

initializeWithState(state, r);

}

updateStateFromTypedArray函数中,BitmapDrawable获取到src属性后,通过BitmapFactory加载图像文件,并读取用户配置的属性,设置BitmapDrawable的其他属性。其他的Drawable的实现方式类似。

android xml animated-rotate,Android Drawable介绍相关推荐

  1. android xml 圆形图片,Android ImageView实现圆角,圆形图片

    UI设计中,为了有更好的效果,用户的头像很多以圆形方式显示,其实现的步骤 1 在res/values/attrs中添加 2 自定义View,CustomImageView.java package c ...

  2. android xml 平铺,Android 图片平铺实现方式

    Android 框架允许创建一个 drawable 包含一个 bitmap 并用于平铺.缩放和对齐处理.当我们需要让背景使用下面图片进行平铺时: 1)第一种利用系统提供的api实现 Bitmap bi ...

  3. android xml获取指定,android:如何从xml文件中获取信息?

    我得到一个程序,从一个链接的服务器获取天气.我已经做了一些将字符串结合到URL的字符串.我现在需要从XML文件中获取信息.android:如何从xml文件中获取信息? 这是我的代码:(我更换了,为了安 ...

  4. android xml 列表展示,Android中ListView实现展示列表数据

    1.在activity_main.xml中添加一个ListView xmlns:tools="http://schemas.android.com/tools" android:l ...

  5. android xml绘制图标,android – 如何为图标制作XML文件

    这是SHARE图标的xml文件.如何为其他图标创建xml? android:width="24dp" android:height="24dp" android ...

  6. android xml正方形,使用Android Constraintlayout创建一排均匀分布的正方形

    我正在努力创建一个由均匀分布的正方形链组成的布局,这些正方形可以填充可用空间.使用Android Constraintlayout创建一排均匀分布的正方形 我到底想要的布局,看起来像这样: 的想法是, ...

  7. android xml画圆,Android自定义View画圆功能

    本文实例为大家分享了Android自定义View画圆的具体代码,供大家参考,具体内容如下 引入布局 xmlns:tools="http://schemas.android.com/tools ...

  8. android xml图片缩放,Android通过自定义ImageView控件实现图片的缩放和拖动的实现代码...

    概述:通过自定义ImageView控件,在xml布局里面调用自定的组件实现图片的缩放. /** * 自定义的ImageView控制,可对图片进行多点触控缩放和拖动 * * @author qiuwan ...

  9. android xml定义阴影,Android 边框阴影XML怎么实现,或者说怎么实现

    在drawable文件夹下建立一个shadow.xml文件,内容如下: android:left="2dp" android:top="2dp"> and ...

  10. android xml ui编辑器,Android Studio(八):使用Layout Editor设计UI

    Android Studio提供了一个高级的布局编辑器,允许你拖拽控件,在编辑XML之后可以实时预览. 在布局编辑器中,你在文字视图和设计视图直接来回切换. 在文字视图中编辑 你可以在文字视图中编辑你 ...

最新文章

  1. 如何解决visual studio2017 install 下载安装极慢的问题
  2. Java是如何加载资源文件的?(源码解毒)
  3. python 拓扑排序 dfs bfs_拓扑排序的DFS和BFS
  4. php文件运行的域名怎么改,discuz论坛更换域名,详细文件修改步骤
  5. php数组常用函数汇总
  6. oracle简体版,oracle|Navicat中文网站
  7. [ExtJs6] 环境搭建及创建项目
  8. Element-UI Form表单 resetFields() 重置表单无效问题
  9. 【Elasticsearch】用Elasticsearch和Raspberry Pi构建一个真实世界的警报
  10. 【英语】舞动奇迹--荡漾我心
  11. 一机难求:折叠手机是未来趋势还是小众需求?
  12. L3-023 计算图 (30 分)--PAT 团体程序设计天梯赛 GPLT
  13. linux msgsend 头文件,Unix/Linux进程间通信
  14. python 多个装饰器的调用顺序
  15. 英伟达登录界面卡住_一汽夏利重组;东风贪腐案行贿者名单? 众泰被申请预重整;尼古拉承认造假;理想英伟达德赛西威将合作;宋PLUS上市[9月17日]...
  16. 金融数据挖掘与分析(三)-案例实战(1)
  17. 进程调度时间计算方式
  18. 【STM32】时钟系统及其结构原理
  19. STM32F103C8T6定时器产生PWM
  20. yarn : 无法加载文件 D:\nodejs\node_global\yarn.ps1,因为在此系统上禁止运行脚本。

热门文章

  1. Google走了,如果没有搜索引擎,大家还会编程吗?同时猜想后面可能会发生的事?
  2. nodejs+vue国产动漫网站论坛数据智能分析系统python django
  3. 可替代(PIN TO PIN)AO3401 MOS管 EV3401
  4. 公式编辑器打的公式能改变颜色吗?
  5. Labview状态机的介绍与程序示例
  6. Qt每天一个小技巧之setProperty 设置属性功能
  7. 【图像处理知识复习】14 Laplacian 二阶微分算子Matlab实现
  8. iOS模拟器中导入视频,获取相册视频,视频缩略图
  9. outlook html格式 效果,outlook中以html格式回复邮件
  10. 12_星仔带你学Java之代码块、final修饰符、基本类型包装类、抽象类、模板方法设计模式讲解