关于 Android(安卓)Drawable Resource学习
关于 Android Drawable Resource学习
声明本文参照官方文档Drawable Resource
Drawable是所有图像类的基类,Android中定义了许多XXDrawable,这给开发带来了极大的方便,许多效果可以直接使用drawable来处理,而无需自己定义view。
首先看一下Drawable这个类的层次关系,如下图:
主要学习常见的Drawable:
1.ShapeDrawable
2.BitmapDrawable
3.ColorDrawable
4.ClipDrawable
5.InsetDrawable
6.ScaleDrawable
7.RoateDrawable
8.LevelListDrawable
9.AnimaitonDrawable
10.StateListDrawable
11.LayerDrawable
12.TransitionDrawable
13.RippleDrawable
ScaleDrawable
ScaleDrawable对应的标签是 ,可以通过设置它的level将指定大小的drawable缩放
概述
这个标签对应的语法(syntax)如下
<?xml version="1.0" encoding="utf-8"?>
上面这个标签的语法中的每个属性又是在哪定义的呢?是不是也像我们自己定义一个控件属性类似呢?
那么我们找到这些属性定义:在R.styleable.ScaleDrawable 这个文件中(在Android源码中位置/framework/base/core/res/res/values/attrs.xml ),很显然也是一个自定义控件而已,只不过是系统定义好的,重复的就不在赘述了,如下:
PS 你可以在线查看系统源码
// 这个属性类型是布尔类型,是否使用本身的大小作为最小值,默认是false
下面重点分析一下ScaleDrawable是如何工作的
@Overridepublic void draw(Canvas canvas) { final Drawable d = getDrawable(); if (d != null && d.getLevel() != 0) { d.draw(canvas); }}
这个draw方法,只有level不为0才会绘制drawable。
当调用drawable.setLevel()的方法后,会回调到onLevelChange()
public final boolean setLevel(int level) { if (mLevel != level) { mLevel = level; return onLevelChange(level); } return false;}
而在ScaleDrawable中重写了这个方法,到里就一目了然了。调用onBoundsChange方法后又去重绘了,这样就可以更新Drawable大小了
@Overrideprotected boolean onLevelChange(int level) { super.onLevelChange(level); onBoundsChange(getBounds()); invalidateSelf(); return true;}
那究竟android:scaleHeight=""
android:scaleWidth=""
和他自身level是如何影响drawable大小的呢?
@Overrideprotected void onBoundsChange(Rect bounds) { final Drawable d = getDrawable(); final Rect r = mTmpRect; final boolean min = mState.mUseIntrinsicSizeAsMin; final int level = getLevel(); int w = bounds.width(); if (mState.mScaleWidth > 0) { final int iw = min ? d.getIntrinsicWidth() : 0; w -= (int) ((w - iw) * (MAX_LEVEL - level) * mState.mScaleWidth / MAX_LEVEL); } int h = bounds.height(); if (mState.mScaleHeight > 0) { final int ih = min ? d.getIntrinsicHeight() : 0; h -= (int) ((h - ih) * (MAX_LEVEL - level) * mState.mScaleHeight / MAX_LEVEL); } final int layoutDirection = getLayoutDirection(); Gravity.apply(mState.mGravity, w, h, bounds, r, layoutDirection); if (w > 0 && h > 0) { d.setBounds(r.left, r.top, r.right, r.bottom); }}
从方法名就可以看出这是用来真正控制缩放效果的,如何控制的呢?
final int iw = min ? d.getIntrinsicWidth() : 0; w -= (int) ((w - iw) * (MAX_LEVEL - level) * mState.mScaleWidth / MAX_LEVEL);
由于min这个属性值通常为false(默认也是false),那么iw一般为零,可以简化为
w -= (int) (w * (10000 - level) * mState.mScaleWidth / 10000);
所以如果level越大,w(drawable)就越大,当level为10000的时候是没有缩放效果的;
如果xml中的缩放比例越大,w(drawable)就越小。
例子
在drawble目录下新建一个xml文件 scale_drawable.xml
<?xml version="1.0" encoding="utf-8"?>
然后在布局文件中引用这个drawable资源
<?xml version="1.0" encoding="utf-8"?>
此时还需要在代码中设置ScaleDrawable的level才会有效果,level默认是0,不显示,将level设置为1即可。
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_drawable); ImageView imageView=(ImageView)findViewById(R.id.image1); ScaleDrawable scaleDrawable=(ScaleDrawable)imageView.getDrawable(); scaleDrawable.setLevel(1); }
Demo效果图
为了对比:第一张是原图,第二张是缩放后的效果图
BitmapDrawable
BitmapDrawable 对应的标签是 ,特殊的是可以通过设置它的平铺模式来变换不同的效果
概述
SYNTAX语法结构:
<?xml version="1.0" encoding="utf-8"?>
重点解释 android:tileMode
android:tileMode=["disabled" | "clamp" | "repeat" | "mirror"]
关键字,这个属性表示图片平铺模式,如果这个属性enable,那么gravity属性会被忽略(ignore)。总共有四种属性值:
- disabled 表示不用这个平铺属性,也是默认值
- repeat 表示图片平铺的效果
- mirror 表示镜像投影的效果
- clamp 可以翻译为紧紧抓住的意思,其效果是图片四周的像素会扩展到周围区域(紧紧靠紧, 个人理解)
android:mipMap=["true" | "false"]
//这个是图片的一种处理技术,
效果图:
disable模式(也是原素材图).png那么我们如何将这个素材图,填满整个控件的背景呢,而且还不变形,类似下面的效果
BitmapDrawable-repeat.png BitmapDrawable-clamp.png BitmapDrawable-mirror.png
如果上面这个mirror模式效果不够明显,那看一下使用Android logo的效果吧
BitmapDrawable-mirror2.png以上效果实现非常简单
在drawable目录下新建一个bitmap_drawable.xml
<?xml version="1.0" encoding="utf-8"?> //分别修改这个模式,即可看到每一个mode的效果
在View中直接设置background引用这个bitmap_drawable.xml 即可
<?xml version="1.0" encoding="utf-8"?>
后记:通常会使用这个属性来平铺一个图片作为背景,可以有效防止失真
当然我们还可以直接用代码来完成上面的效果,例如
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.pic_bg_01_min); BitmapDrawable drawable = new BitmapDrawable(getResources(), bitmap); drawable.setTileModeXY(Shader.TileMode.REPEAT, Shader.TileMode.REPEAT); drawable.setDither(true); drawable.setAntiAlias(true); drawable.setFilterBitmap(true); ImageView view = (ImageView) findViewById(R.id.image); view.setBackgroundDrawable(drawable);
InsetDrawable
InsetDrawable在xml中对应的标签是
官方这样解释InsetDrawable的应用场景:
This is used when a View needs a background that is smaller than the View's actual bounds.
当一个view所需要的背景图比他自身的实际边界要小的时候,通常用这个InsetDrawable。
概述
SYNTAX语法结构:
<?xml version="1.0" encoding="utf-8"?> // 上面这四个属性值类型是dimension,即表示dimension值或者引用那种@dimen // android:insetLeft表示的是drawable距离左边的距离,同理其他几个类似
说到这你可能还不造是什么效果呢?OK,来看个实际问题吧
效果图.png这个效果是这样的,ListView的点击效果充满整个宽度,而分割线却距离两边都有一个距离,显然不能单纯的使用默认divider设置一个分割线,这个时候该InsetDrawable该登场了!
在drawable目录下定义一个inset_listview_divider.xml文件
然后在listvew中引用这个drawable即可
mark未完待续
更多相关文章
- Kotlin For Android介绍
- 【Android】入门案例(一)——简单登录
- 【Android】安卓布局文件中xmlns属性
- Android仿微信雷达扫描效果的实现方法
- android -------- GifView 显示gif图片
- Animation用法_animation动画效果
- [Accessibility] Missing contentDescription attribute on imag
- Android开发--Intent-filter属性详解 (转载)
- [Android记录]android中的shape