Android : Drawable


Drawable 可理解为可绘制物,表示可以绘制在Canvas上的对象。
为UI配置背景、图片、动画等界面效果时要用到Drawable。

Drawable的方法:
inflate: 从XML中解析属性,子类需重写
setAlpha: 设置绘制时的透明度
setBounds: 设置Canvas为Drawable提供的绘制区域
setLevel: 设置Drawable的Level值,在ClipDrawable RotateDrawable ScaleDrawable AnimationDrawable等Drawable中有重要作用,区间为[0, 10000]
draw(Canvas): 绘制到Canvas上,子类必须重写。

StateListDrawable

根据对象的状态,使用多个不同的图像来表示同一个图形。
界面控件的状态有:获取焦点/失去焦点、按下状态、可点击状态/不可点击状态、选中状态/未选中状态、勾选状态/未被勾选状态、激活状态/未被激活状态等。
在XML文件中描述状态列表。每个图形由<selector>元素内的<item>元素表示。

ShapeDrawable

使用Shape来进行简单UI的开发,可以在一定程度上减少图片的使用,降低App的体积,一般用shape定义的xml文件存放在drawable目录下。

  1. 支持的形状: android:shape=“rectangle”
    rectangle: 矩形,默认的形状,可以画出直角矩形、圆角矩形、弧形等
    oval: 椭圆形,用得比较多的是画正圆
    line: 线形,可以画实线和虚线
    ring: 环形,可以画环形进度条
  2. solid用来设置形状填充的颜色
    只有android:color属性<solid android:color=“#FF0000” />
  3. padding: 设置内容区域离边界的间距,可分别设置左右上下的距离。默认情况下,组件相互之间是紧紧靠在一起
<padding
    android:bottom="15dp"
    android:left="15dp"
    android:right="15dp"
    android:top="15dp" />
  1. gradient用来设置形状的渐变颜色
<gradient
    android:centerX="0.5"        相对X的渐变位置
    android:centerY="0.5"       相对Y的渐变位置
    //在type不为linear情况下,这两个属性表示中心点所在的百分比
    //在type为linear情况下,用于改变中间颜色相对的位置。X对左右的渐变有用,而Y对上下的渐变有用
    android:startColor="#FF0000"   渐变开始点的颜色
    android:centerColor="#FFFFFF" 中间颜色的过渡
    android:endColor="#00FFFF"/>   渐变结束点的颜色	
     android:angle="270"               渐变的角度:0(从左到右)90(从下到上)180(从右到左)270(从上到下)	
    android:type="linear" />            type:渐变的类型 默认为linear 线性渐变。radial 放射渐变,设置该项时,android:gradientRadius也必须设置	
    android:gradientRadius	渐变半径 android:type=radial 才有作用	
  1. corners用来设置圆角,只适用于rectangle类型,可分别设置四个角不同半径的圆角,当设置的圆角半径很大时就变成弧形边了
<corners android:radius="15dp" />  四个圆角半径,会被下面每个特定的圆角属性重写
android:topLeftRadius 左上角的半径
android:topRightRadius 右上角的半径
android:bottomLeftRadius 左下角的半径
android:bottomRightRadius 右下角的半径
  1. stroke用来设置描边,可描成实线或虚线
<stroke	
    android:width="2dp"             描边的宽度	
    android:color="#FF0000"         描边的颜色	
    android:dashGap="4dp"           设置虚线时的横线之间的距离	
    android:dashWidth="4dp" />      设置虚线时的横线长度	
  1. size 用来设置图形的尺寸,默认是View的宽度和高度
<size android:width="60dp"	
    android:height="60dp" />

line: 线形,可以画实线和虚线。不过一般使用线都是直接View的。通过设置stroke可以设置线的样式(颜色、虚线还是实线等)

ring:圆环
android:innerRadius 内环的半径
android:thickness 环的厚度

RotateDrawable

可以通过调用方法setLevel来控制旋转角度的大小,取值在0~10000之间。
把起始角度和终点角度之间的角度均等分为10000份,当level等于0时处于起始位置,当level等于10000时处于终点位置

<rotate xmlns:android="http://schemas.android.com/apk/res/android"  	
    android:drawable="@drawable/ic_launcher"  	
    android:visible="true"  初始的可见性状态	
    android:fromDegrees="0"  起始的角度度数	
    android:toDegrees="180"  结束的角度度数,负数表示逆时针,正数表示顺时针	
    android:pivotX="50%"  旋转中心的X坐标	
    android:pivotY="50%">  旋转中心的Y坐标	
</rotate>	

InsetDrawable

可以把一个 drawable 资源嵌入到其他的资源内部,并且在四周可以留下边距
当level=0时图片又没有显示,所以一般设置level为1,图片会根据xml中的android:scaleWidth和android:scaleHeight进行相应缩放

LayerDrawable

layer-list创建出来的是图层列表,也就是一个drawable图形
原理类似RelativeLayout(或FrameLayout).layer-list中的item是按照顺序从下往上叠加的,即先定义的item在下面,后面的依次往上面叠放.
可以通过控制后添加图层距离最底部图层的左上右下的四个边距等属性,得到不同的显示效果

ClipDrawable

允许对一个Drawable进行剪裁操作,在绘制的时候只绘制剪裁的部分
通过setLevel实现图片裁剪,范围:0-10000

ScaleDrawable

ScaleDrawable与ClipDrawable类似,可以根据设置的level值对drawable进行缩放,但与ClipDrawable不同的是ScaleDrawable还可以根据设置android:scaleWidth和android:scaleHeight进行相应百分比的缩放。

<?xml version="1.0" encoding="utf-8"?>
<scale
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/drawable_resource"
    android:scaleGravity=["top" | "bottom" | "left" | "right" | 
    				"center_vertical" | "fill_vertical" | "center_horizontal" |
    				"fill_horizontal" | "center" | "fill" | "clip_vertical" | "clip_horizontal"]
    android:scaleHeight="percentage"
    android:scaleWidth="percentage" />

元素:
scale定义一个ScaleDrawable,必须作为根元素。
android:drawable Drawable 资源。必须的。引用一个drawable资源。
android:scaleHeight 缩放的高度,以百分比的方式表示drawable的缩放。如:100%,12.5%。
android:scaleWidth 缩放的宽度,以百分比的方式表示drawable的缩放。形式例如:100%,12.5%。
android:scaleGravity 指定缩放后的gravity的位置。必须是下面的一个或多个值(多个值之间用”|”分隔)
top 将这个对象放在容器的顶部,不改变其大小。
bottom 将这个对象放在容器的底部,不改变其大小。
left 将这个对象放在容器的左部,不改变其大小。默认值。
right 将这个对象放在容器的右部,不改变其大小。
center_vertical 将对象放在垂直中间,不改变其大小。
fill_vertical 如果需要的话,该对象的垂直尺寸将增加,以便完全填充它的容器。
center_horizontal 将对象放在水平中间,不改变其大小。
fill_horizontal 如果需要的话,该对象的水平尺寸将增加,以便完全填充它的容器。
center 将对象放置在其容器的中心和水平轴的中心位置,而不改变它的大小。
fill 如果需要的话,该对象的水平和垂直方向的大小将增加,使得完全填充它的容器。
clip_vertical 可以设置为在其容器边界上的顶部和/或底部边缘的附加选项。该剪辑是基于垂直gravity:一个顶部gravity剪辑的底部边缘,底部重力剪辑的顶部边缘,既不剪辑两个边。
clip_horizontal 与clip_vertical类似,只是剪辑是基于水平gravity。
来看下面的例子,在res/drawable/scale.xml中定义一个ScaleDrawable:

<ImageView   
    android:id="@+id/imgView"  
    android:src="@drawable/scale"  
    android:layout_width="wrap_content"  
    android:layout_height="wrap_content"/>

但是如果直接运行,发现并没有显示图片,查看ScaleDrawable的源码,发现draw方法有判断getLevel() != 0才绘制。在没有setLevel时,默认getLevel都是0

android/platform/frameworks/base/graphics/java/android/graphics/drawable/ScaleDrawable.java:

@Override
    public void draw(Canvas canvas) {
        final Drawable d = getDrawable();
        if (d != null && d.getLevel() != 0) {
            d.draw(canvas);
        }
    }

所以如果想正常显示图片,还需要设置drawable的level。

ImageView imageview = (ImageView) findViewById(R.id.image);
    ScaleDrawable drawable = (ScaleDrawable) imageview.getDrawable();
    drawable.setLevel(1);

那么为什么设置了level之后就会显示图片呢,而且我们应该设置多大呢?我们继续看源码,当设置level之后会触发onLevelChange事件:

@Override
    protected boolean onLevelChange(int level) {
        super.onLevelChange(level);
        onBoundsChange(getBounds());
        invalidateSelf();
        return true;
    }

可以看到在onLevelChange中又调用了onBoundsChange

@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);
        }
    }

在计算图片长宽的时的变量iw:
final int iw = min ? d.getIntrinsicWidth() : 0;
其中min = mState.mUseIntrinsicSizeAsMin;
mUseIntrinsicSizeAsMin的值是在xml文件中设置,true/false

state.mUseIntrinsicSizeAsMin = a.getBoolean(
R.styleable.ScaleDrawable_useIntrinsicSizeAsMinimum, 
state.mUseIntrinsicSizeAsMin)

一般没有设置这个值,默认为false,所以iw和ih也默认为0,MAX_LEVEL为10000。
那么上面的表达式就可以简化为
w -= (int) (w * (10000 - level) * mState.mScaleWidth / 10000);
h -= (int) (h * (10000 - level) * mState.mScaleHeight / 10000);

如果设置level=10000,即为:
w -= 0 h -= 0 也就是图片原始大小,没有缩放效果。
当level=0时图片又没有显示,所以我们一般设置level为1,这样图片就会根据xml中的android:scaleWidth和android:scaleHeight进行相应的缩放了。如设置长宽缩放比例为50%,那么图片长和宽都是原来的一半,图片大小实际是原来大小的四分之一。

点九图

.9.PNG,安卓开发里面的一种特殊格式的图片。
具有可拉伸的特性,android会自动调整它的大小,来使图像在充当背景时可以在界面中自适应展示。
Android有很多的分辨率,当圆角矩形控件在被拉伸放大时,圆角部分会出现模糊的情况。
点九切图不同,可以保证不管上下左右拉伸放大,都可以保持原有的清晰度。普通的拉伸效果圆角部分也跟着变大,点九下的效果圆角部分还是原来大小。

点九切图法: 相当于把一张png图分成了9个部分(九宫格)。可以保证在不同的分辨率下,及界面改变方向后,界面上的图形不会因为长宽的变化而产生拉伸,造成图形的失真变形。
ps: 盖了一座房子。觉得小了,需要再宽点再长点。只拆四个角,然后延长,再把四个角按照原来的样子重新垒好。

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

春夏与冬

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值