谈谈Android的中的Drawable

一、Drawable

Drawable是对安卓中所有可绘制图像的抽象,也就是说安卓中的图像是以Drawable形式存在的。View显示图像时就是以View为载体通过Canvas吧Drawable渲染到画布上。

1、Drawable有哪些优点呢?

drawable 优点主要有如下两点:

  • 使用简单,比自定义view的成本要低。
  • 非图片类型的drawable占用空间较小,对减小apk的体积有很大的帮助。
2、drawable内宽高的概念
    getIntrinsicWidth()
    getIntrinsicHeight()

drawable的内宽高这个参数比较重要,但并不是所有的drawable都有内部宽高:

  • 图片所形成的drawable有内部宽高。其内部宽高就是图片的宽高。
  • 颜色所形成的drawable没有内部宽高的概念。
  • drawable的内部宽高不等同他的大小,drawable是没有大小概念的。drawable被用作view的背景时drawable会被拉伸到view的同等大小。
2、安卓提供的Drawable实现类

在这里插入图片描述
安卓中提供了很多Drawable实现类,常见的如下:

  • ShapeDrawable
  • BitmapDrawable
  • NinePatchDrawable
  • StateListDrawable
  • LayerDrawable
  • LevelListDrawable
  • TransactionDrawable
  • InsetDrawable
  • ScaleDrawable
  • ClipDrawable

接下来便一一熟悉下常见的drawable~

二、常见的Drawable实现类

1、ShapeDrawable

开发中最常见的drawable类,对应xml的shape标签。

what???平时开发中给按钮一个圆角矩形的背景,这不正是经常用的吗?原来在安卓project res文件夹 ->drawable目录上鼠标右键->new ->drawable resource file 创建的xml文件内部使用的shape根标签就对应java类的ShapeDrawable。豁然开朗哈哈哈哈。

(1)shape作为view的背景的效果预览
在这里插入图片描述
(2)xml代码如下

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">

    <corners android:radius="5dp" />
    <gradient
        android:angle="0"
        android:endColor="@color/colorPrimaryDark"
        android:startColor="@color/green" />
    <padding
        android:bottom="2dp"
        android:left="2dp"
        android:right="2dp"
        android:top="2dp" />

    <size
        android:width="50dp"
        android:height="50dp" />

    <!-- 内部填充-->
    <!--<solid android:color="@color/colorAccent" />-->

    <stroke
        android:width="3dp"
        android:color="@color/colorAccent"/>

</shape>

shape:根标签,其内部可以有corners、gradient、padding、size、soild、stroke这些子标签。shape标签属性如下:

1、shape属性:表示图形形状。值可以为:

  • 属性值rectangle:矩形,默认的形状。
  • 属性值oval:椭圆
  • 属性值line:横线
  • 属性值ring:圆环

corners:表示圆角,corner标签属性如下:

1、属性radius:为四个角同时指定圆角大小,我们也可以单独为每个角指定圆角。
2、属性topLeftRadius:单独为左上角指定圆角大小。
3、属性topRightRadius:单独为右上角指定圆角大小。
4、属性bottomLeftRadius:单独为左下角指定圆角大小。
5、属性bottomRightRadius:单独为右下角指定圆角大小。

gradient:gradient渐变色,与soild标签互相排斥,二者只能存在其一。soild表示颜色填充,gradient表示渐变效果。gradient标签属性如下:

1、angle属性:渐变角度,默认为0,代表从左往右渐变,数值必须为45的倍数。

  • 90:自上而下渐变
  • 180:自右向左渐变
  • 等等角度

2、startColor、endColor:开始/结束时的渐变色
4、centerColor:渐变的中间色
5、useLevel:一般为false,当drawable作为StateListDrawable使用时为true
6、type:渐变类型,值可为:

  • linear:线性渐变
  • radial :径向渐变
  • sweep:扫面线渐变

7、gradientRadius:渐变半径,仅当type为radial 时生效。

soild:图形内部颜色填充,soild与gradient效果二者只能存在一种。soild标签具有属性如下:

1、属性color:图形内填充色。

stroke:图形的描边,参考效果图标记1。stroke标签具有属性如下:

1、width:描边宽度
2、color:描边颜色
3、dashWidth :描边为虚线,代表虚线宽度(与dashGap合用生效)
4、dashGap:虚线线段之间的间隔距离。(与dashWidth合用生效)

size:表示shape的大小,当view有自己的宽高时,shape会自适应view宽高,此时shape宽高不会生效。当view为wrap_content时对应的shape属性就会生效。shape标签属性值如下

1、width: shape的宽
2、height:shape的高

注意:shape有四种形状,但是line和ring这两个形状使用时,必须通过stroke这个子标签来指定线宽和颜色,否则无法看到效果。ring有特殊的5个属性如下:

1、innerRadius:圆环内半径,和innerRadioRatio同时存在时以innerRadius为准。
2、 tickness:圆环厚度,即为外半径减去内半径的大小,和ticknessRatio同时存在时以ticknessRadius为准。
3、 innerRadioRatio:半径占整个drawable宽度的比例
4、ticknessRatio:厚度占整个drawable宽度的比例
5、useLevel 一般为false

2、BitmapDrawable

在这里插入图片描述
上面几种方式不是平时我们使用代码为imageview设置图片的常见形式吗?其实上述代码中的方式就是给view设置了一个BitmapDrawable作为View的背景。

BitmapDrawable是最简单的drawable,表示一张图片。在开发中我们可以直接引用原始资源的图片即可,也可以通过xml方式来描述他。只是通过xml来描述的BitmapDrawable可以设置更多的效果:

<?xml version="1.0" encoding="utf-8"?>
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
        android:src="@drawable/ic_launcher"
        android:antialias="true"
        android:dither="true"
        android:filter="true"
        android:mipMap="false"
        android:tileMode="mirror">

</bitmap>

如上xml文件设置给view作为背景效果如下~

在这里插入图片描述
可见bitmap标签下属性不少,其实我们拿来使用的通常只有tileMode和src,其他的都使用默认值即可。具体属性如下:

1、src:加载图片,以下的属性就操作这张图片。
2、antialias:图片抗锯齿,true表示开启,开启后让图片变得平滑,同时在一定程度上降低图片的清晰度,但是这个降低的幅度可以忽略。一般开启。
3、 dither:抖动效果,true表示开启,当图片的像素配置和手机的像素配置不一致时,开启这个可以让高质量的图片在低质量的屏幕上还能保持较好的显示效果。一般开启。
4、filter:过滤效果,true表示开启,当图片被拉伸或者被压缩时,开启过滤效果可以保持较好的效果。
5、gravity:和我们平时使用的gravity效果一样。当图片的尺寸小于容器的尺寸时,设置此选项可以对图片进行定位。gravity有几个特殊属性值:

  • fill_vertical :图片竖直填充(改变原图大小)
  • fill: 图片水平竖直填充(改变原图大小,默认值就是fill)
  • clip_vertical:图片竖直裁剪(较少使用)

6、minMap:图像相关的处理技术,纹理映射,一般默认为false
7、tileNode:平铺模式四个属性值如下:

  • disable :不开启平铺模式(默认)
  • mirror:水平和竖直方向上镜面效果(如上效果图)
  • repeat:水平和竖直平铺。
  • clamp:四周的像素会扩散到周围区域
3、NinePatchDrawable

.9图片,qq,微信发消息我们都知道吧,无论消息内容多大多小,这个框框背景都会自适应拉伸。没错这就是NinePatchDrawable的功能。

这个类对应的xml标签为nine-patch,当然他和BitmapDrawable用法一致,就是src加载的为.9图片。甚至我们使用bitmap标签也可以,加载.9图片即可,同样实现NinePatchDrawable功能。

4、StateListDrawable

这个java类或许你没见过,但是 selector这个标签我们都十分熟悉吧,点击按钮是一种颜色,松开按钮是一种颜色,哎哎哎。。这不就是平时使用的selector的功能吗,没错StateListDrawable类就对应selector标签。

selector:根标签,内部可以有item标签,每种item标签都代表一种状态。selector跟标签有如下属性:

1、constantSize:StateListDrawable的固有大小是否随着状态的改变而改变 。因为状态改变时会切换到具体的drawable,不同的drawable有不同的固有大小。true表示不变,这时固有大小是内部Drawable中的最大值的固有大小。false改变,false是默认值。
2、dither:是否开启抖动,上文已经介绍过。
3、variablePadding:StateListDrawable内的drawable是否随着状态的改变而改变,true表示随着改变。false表示StateListDrawable的padding是内部所有drawable的padding最大值默认为false,不建议开启。

item标签:selector子标签,每个item代表一个具体drawable状态。按钮经常使用的selector栗子如下:松开击按钮为colorPrimary色,摁着按钮不松开为colorAccent色。

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"
        android:constantSize="true"
        android:dither="true"
        android:variablePadding="false">
    <item android:drawable="@color/colorAccent" android:state_pressed="true"/>
    <item android:drawable="@color/colorPrimary" android:state_pressed="false"/>
<!--<item android:drawable="@color/colorPrimaryDark"/> false不设置也可以,
                                                       这样代表默认状态-->
</selector>

状态改变时系统会自上而下寻找对应的状态,没有对应的状态时,就会使用默认的。

selector的状态state_xxx:上面举了个state_pressed 的栗子,还有很多我们可以自己搜索练习下,,,,,

selector中使用shape:selector也可以自定义view的drawable背景 ,在item下使用shape就行了

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:state_enabled="true">
        <shape>
            <solid android:color="@color/color_btn_unclick" />
            <size android:width="62dp" android:height="26dp" />
            <corners android:radius="8dp" />
        </shape>
    </item>

    <item android:state_enabled="false">
        <shape>
            <solid android:color="@color/color_btn_click" />
            <size android:width="62dp" android:height="26dp" />
            <corners android:radius="8dp" />
        </shape>
    </item>

</selector>

在这里插入图片描述
按钮的背景色 点击是一种状态,未点击是一种状态,当然你也可以设置为摁下是一种状态,松开是一种状态,是需求而定~

5、LayerDrawable

对应xml标签的 layer-list标签,它表示一种层次化的drawable集合,将不同的drawable,放置在不同的层面上从而达到一种叠加效果。

layer-list标签:根标签。

item :layer-list的唯一子标签,表示不同的drawable,item下可以有如下常见子标签

  • layer-list:
  • shape:
  • selector:
  • bitmap
  • color
  • level-list
  • nine-patch

item标签还可以有如下常见属性:top、bottom、left、right 、item标签的属性,表示drawable相对view的偏移量。

注意:

  • 默认情况下layer-list内的所有drawable都会缩放到view的大小。对于bitmap来说需要使用gravity来控制显示效果。
  • 2、layer-list有层次概念,下面的item会覆盖上面的item,合理运用可以实现一些特殊的叠加效果。

一个栗子:仿微信 文本输入框(给EditText设置这个drawable)
在这里插入图片描述

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <!--  1、  整个背景设置为浅绿-->
    <item>
        <shape android:shape="rectangle">
            <solid android:color="@color/light_green"/>
        </shape>

    </item>
<!--    2、覆盖1只留底部1dp的线-->
    <item
            android:bottom="2dp">
        <shape android:shape="rectangle">
            <solid android:color="@color/white"/>
        </shape>

    </item>
<!--   3、 上部边界处理-->
    <item android:bottom="6dp">
        <shape android:shape="rectangle">
            <solid android:color="@color/white"/>
        </shape>

    </item>

<!-- 下层的item 覆盖上层-->
</layer-list>
6、LevelListDrawable

和LayerDrawable、 StateLiatDrawable一样也是一个Drawable集合。只是LevelListDrawable的每个Drawable都有一个等级我们设置好后,通过代码可以改变显示不同的层级。

举个栗子:点击按钮,Imageview切换颜色。

<?xml version="1.0" encoding="utf-8"?>
<level-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item
            android:drawable="@color/light_green"
            android:maxLevel="0"
           />

    <item
            android:drawable="@color/colorAccent"
            android:maxLevel="1"/>

</level-list>
public class MainActivity extends AppCompatActivity {

    private ImageView imageView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        imageView = findViewById(R.id.img_view);
        imageView.setImageResource(R.drawable.level_list_demo);
        imageView.setImageLevel(0);
    }

    public void doClick(View view) {
        Log.i("bla", "doClick: ");
        imageView.setImageLevel(1);
    }
}

item标签下的属性:

  • drawable:drawable资源
  • maxValue、minLevel : 最大级别值,最小级值。等级范围[0,10000] 0为默认值。

注意:

  • 作为背景时用drawable的setLevel()
  • 作为Imageview的ImageResource时用setImageLevel

常见使用场景:手机信号变化图

在这里插入图片描述

7、TransactionDrawable

对应标签xml的transaction标签,可以实现drawable之间的变化效果,类似动画。

举个栗子

<?xml version="1.0" encoding="utf-8"?>
<transition xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@color/colorAccent" />
    <item android:drawable="@color/black"/>

</transition>

设置给textview作为bg后开启效果~

        TextView textView = findViewById(R.id.tv_text);
        TransitionDrawable transitionDrawable = (TransitionDrawable) textView.getBackground();
        transitionDrawable.startTransition(2000);
8、InsetDrawable

对应inset 标签。可以将其他的drawable内嵌到自己当中,当一个view希望背景比自己的实际区域小时可以用这个,类似于控件的padding。

直接来个栗子:

在这里插入图片描述

<?xml version="1.0" encoding="utf-8"?>
<inset xmlns:android="http://schemas.android.com/apk/res/android"
       android:inset="15dp">
    <!-- inset 类似padding使用 也可以单独 insetXXX例如 insetBottom-->
    <shape android:shape="rectangle">
        <solid android:color="@color/colorPrimaryDark"/>
    </shape>
</inset>
9、ScaleDrawable

对应xml的 scale标签表示缩放图片。

直接来个栗子:

<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
        android:drawable="@drawable/ic_launcher"
        android:scaleWidth="70%"
        android:scaleHeight="70%"
        android:scaleGravity="center">
<!--
scaleWidth
scaleHeight  缩放宽高(按照比例缩放)
-->

</scale>
java中:
TextView textView = findViewById(R.id.tv_text);
        ScaleDrawable scaleDrawable = (ScaleDrawable) textView.getBackground();
        scaleDrawable.setLevel(1);
        // level范围[0,20000] 默认为0,无效果。
        //  level必须有且不为0,否则无效果。
10、ClipDrawable

对应xml的clip标签。作用根据等级裁剪drawable,通过clipOrientation和gravity属性来一起控制。

举个栗子:

<?xml version="1.0" encoding="utf-8"?>
<clip xmlns:android="http://schemas.android.com/apk/res/android"
      android:drawable="@drawable/ic_launcher"
        android:clipOrientation="vertical"
        android:gravity="center">
</clip>

java

    TextView textView = findViewById(R.id.tv_text);
        ClipDrawable clipDrawable = (ClipDrawable) textView.getBackground();
        clipDrawable.setLevel(8000); 
        // level [0,10000]  0 完全裁剪 drawable不可见,10000不裁剪
        // 8000 表示  上面裁剪20%

三、自定义Drawable

drawable的使用范围比较单一:

  • 作为imageView中的图像来显示
  • 作为view 的背景

下面康康如何自定义一个drawable:

/**
 * Created by sunnyDay on 2019/6/17 21:05
 * <p>
 * 自定义drawable
 */
public class CustomDrawable extends Drawable {
    private Paint mPaint;

    /**
     * 声明对象时就初始化画笔
     */
    public CustomDrawable(int color) {
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setColor(color);
    }

    @Override
    public void draw(Canvas canvas) {
        Rect rect = getBounds();
        float centerX = rect.exactCenterX(); //返回矩形的中心x值
        float centerY = rect.exactCenterY();// 返回矩形的中心y值
        canvas.drawCircle(centerX, centerY, Math.min(centerX, centerX), mPaint);
    }

    @Override
    public void setAlpha(int alpha) {
        mPaint.setAlpha(alpha);
        invalidateSelf();
    }

    @Override
    public void setColorFilter(ColorFilter colorFilter) {
        mPaint.setColorFilter(colorFilter);
        invalidateSelf();
    }

    @Override
    public int getOpacity() {
        return PixelFormat.TRANSPARENT;
    }
}

end

参考<安卓开发艺术探索>

  • 4
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值