android getdrawable theme,关于 Android Drawable Resource学习

关于 Android Drawable Resource学习

Drawable是所有图像类的基类,Android中定义了许多XXDrawable,这给开发带来了极大的方便,许多效果可以直接使用drawable来处理,而无需自己定义view。

首先看一下Drawable这个类的层次关系,如下图:

6460d5788406

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)如下

xmlns:android="http://schemas.android.com/apk/res/android"

//xmlns:android 这个是定义XML命名空间的,是必须的,且值必须为这个

android:drawable="@drawable/drawable_resource"

//android:drawable 这个是来引用一个drawable资源的,是必须的

android:scaleGravity=["top" | "bottom" | "left" | "right" | "center_vertical" |

"fill_vertical" | "center_horizontal" | "fill_horizontal" |

"center" | "fill" | "clip_vertical" | "clip_horizontal"]

//android:scaleGravity 关键字。指定缩放后的gravity的位置。必须是上面可选值中的一个或多个(多个用‘|’分隔)。

android:scaleHeight="percentage"

// android:scaleHeight 缩放的高度,以百分比来表示drawable的缩放,比如50%

android:scaleWidth="percentage"

// android:scaleWidth 缩放的宽度,以百分比来表示drawable的缩放,比如50%

/>

上面这个标签的语法中的每个属性又是在哪定义的呢?是不是也像我们自己定义一个控件属性类似呢?

那么我们找到这些属性定义:在R.styleable.ScaleDrawable 这个文件中(在Android源码中位置/framework/base/core/res/res/values/attrs.xml ),很显然也是一个自定义控件而已,只不过是系统定义好的,重复的就不在赘述了,如下:

// 这个属性类型是布尔类型,是否使用本身的大小作为最小值,默认是false

下面重点分析一下ScaleDrawable是如何工作的

@Override

public 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大小了

@Override

protected boolean onLevelChange(int level) {

super.onLevelChange(level);

onBoundsChange(getBounds());

invalidateSelf();

return true;

}

那究竟android:scaleHeight="" android:scaleWidth=""和他自身level是如何影响drawable大小的呢?

@Override

protected 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

android:drawable="@drawable/girl"

android:scaleGravity="left"

android:scaleHeight="40%"

android:scaleWidth="40%"

/>

然后在布局文件中引用这个drawable资源

xmlns:tools="http://schemas.android.com/tools"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:paddingBottom="@dimen/activity_vertical_margin"

android:paddingLeft="@dimen/activity_horizontal_margin"

android:paddingRight="@dimen/activity_horizontal_margin"

android:paddingTop="@dimen/activity_vertical_margin"

tools:context="com.smart.myapplication.DrawableActivity">

android:id="@+id/image2"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:scaleType="centerInside"

android:src="@drawable/girl" />

android:id="@+id/image1"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:layout_below="@id/image2"

android:layout_marginTop="50dp"

android:scaleType="centerInside"

android:src="@drawable/scale_drawable" />

此时还需要在代码中设置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效果图

为了对比:第一张是原图,第二张是缩放后的效果图

6460d5788406

ScaleDrawable效果.png

BitmapDrawable

BitmapDrawable 对应的标签是 ,特殊的是可以通过设置它的平铺模式来变换不同的效果

概述

SYNTAX语法结构:

xmlns:android="http://schemas.android.com/apk/res/android"

android:src="@[package:]drawable/drawable_resource"

android:antialias=["true" | "false"]

// 是否开启图片抗锯齿功能,一般开启,设置为true

android:dither=["true" | "false"]

//是否开启抖动效果,一般开启后可以让图形显示质量更好(不同分辨率的屏幕),设置为true

android:filter=["true" | "false"]

// 是否开启过滤效果,当图片被拉伸或压缩,开启后会显示更好的效果,建议开启

android:gravity=["top" | "bottom" | "left" | "right" | "center_vertical" |

"fill_vertical" | "center_horizontal" | "fill_horizontal" |

"center" | "fill" | "clip_vertical" | "clip_horizontal"]

android:mipMap=["true" | "false"]

//这个是图片的一种处理技术

android:tileMode=["disabled" | "clamp" | "repeat" | "mirror"] />

重点解释 android:tileMode

android:tileMode=["disabled" | "clamp" | "repeat" | "mirror"]

关键字,这个属性表示图片平铺模式,如果这个属性enable,那么gravity属性会被忽略(ignore)。总共有四种属性值:

disabled 表示不用这个平铺属性,也是默认值

repeat 表示图片平铺的效果

mirror 表示镜像投影的效果

clamp 可以翻译为紧紧抓住的意思,其效果是图片四周的像素会扩展到周围区域(紧紧靠紧, 个人理解)

android:mipMap=["true" | "false"]

//这个是图片的一种处理技术,

效果图:

6460d5788406

disable模式(也是原素材图).png

那么我们如何将这个素材图,填满整个控件的背景呢,而且还不变形,类似下面的效果

6460d5788406

BitmapDrawable-repeat.png

6460d5788406

BitmapDrawable-clamp.png

6460d5788406

BitmapDrawable-mirror.png

如果上面这个mirror模式效果不够明显,那看一下使用Android logo的效果吧

6460d5788406

BitmapDrawable-mirror2.png

以上效果实现非常简单

在drawable目录下新建一个bitmap_drawable.xml

android:antialias="true"

android:src="@mipmap/pic_bg_01_min" //引用一个图片

android:dither="true"

android:filter="true"

android:gravity="center"

android:tileMode="clamp"> //分别修改这个模式,即可看到每一个mode的效果

在View中直接设置background引用这个bitmap_drawable.xml 即可

xmlns:tools="http://schemas.android.com/tools"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:paddingBottom="@dimen/activity_vertical_margin"

android:paddingLeft="@dimen/activity_horizontal_margin"

android:paddingRight="@dimen/activity_horizontal_margin"

android:paddingTop="@dimen/activity_vertical_margin"

tools:context="com.smart.myapplication.BitmapDrawableActivity">

android:layout_width="match_parent"

android:layout_height="match_parent"

android:background="@drawable/bitmap_drawable"

android:scaleType="centerInside"/>

后记:通常会使用这个属性来平铺一个图片作为背景,可以有效防止失真

当然我们还可以直接用代码来完成上面的效果,例如

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语法结构:

xmlns:android="http://schemas.android.com/apk/res/android"

// 必须的,命名空间,且值必须为这个,不多解释

android:drawable="@drawable/drawable_resource"

// 必须的,指定引用的drawable资源

android:insetTop="dimension"

android:insetRight="dimension"

android:insetBottom="dimension"

android:insetLeft="dimension" />

// 上面这四个属性值类型是dimension,即表示dimension值或者引用那种@dimen

// android:insetLeft表示的是drawable距离左边的距离,同理其他几个类似

说到这你可能还不造是什么效果呢?OK,来看个实际问题吧

6460d5788406

效果图.png

这个效果是这样的,ListView的点击效果充满整个宽度,而分割线却距离两边都有一个距离,显然不能单纯的使用默认divider设置一个分割线,这个时候该InsetDrawable该登场了!

在drawable目录下定义一个inset_listview_divider.xml文件

android:insetLeft="@dimen/theme_padding_17dp"

android:insetRight="@dimen/theme_padding_17dp" >

然后在listvew中引用这个drawable即可

android:id="@+id/city_list"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:cacheColorHint="@android:color/transparent"

android:dividerHeight="0.3dp"

android:divider="@drawable/inset_listview_divider"

android:scrollbars="none" />

mark未完待续

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值