【Android学习】Drawable

本文详细介绍了Drawable在Android中的使用方法,包括其优点、优化策略、多种类型(如BitmapDrawable、ShapeDrawable等)及其属性设置,并提供了自定义Drawable的示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1,概念

Drawable可以在Canvas上进行绘制。
一般用作View的背景来使用。此时Drawable被拉做View的大小。
最常见的颜色和图片都可以是一个Drawable。

1)优点

使用简单:比自定义View成本低。
占用空间校:非图片类型的Drawable占用空间小,可以减小apk的大小。

2)优化

①在onDraw最终不用创建新的局部对象。
onDraw被频繁调用,创建了新的局部对象后,会一瞬间产生大量的临时对象,这样占用内存并导致系统频繁gc。
②onDraw中不做耗时任务。

2,分类

1)BitmapDrawable

表示一张图片。

①属性

android:src   
--图片的资源id
android:antialias  
--是否开启图片抗锯齿功能。开启后让图片变平滑,但降低清晰度。
android:dither   
--是否开启抖动效果。当图片像素配置和手机屏幕的像素配置不一致时,可以让高质量的图片在低质量的屏幕上还能保持较好的显示效果,不至于失真。
android:filter
--是否开启过滤效果。当图片尺寸被拉伸或者压缩时,可保持较好的显示效果。
android:gravity
--图片小于容器尺寸,可通过此项定位图片。
--top、bottom、left、right 不改变图片大小。
--center_vertical、fill_vertical、center、fill
--clip_vertical  竖直方向的裁剪
android:mipMap
--图像处理技术:纹理映射。默认为false
android:tileMode
--平铺模式
--disabled 关闭此项,默认值
--clamp(图片四周的像素会扩展到周围区域)、repeat、mirror  开启平铺模式,gravity属性将失效。

2)ShapeDrawable

通过颜色构造的图片。由shape标签xml来实现。

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle" >    
    <!-- 填充 -->
    <solid android:color="@color/white" /><!-- 填充的颜色 -->
    <!-- 大小 -->
    <size 
        android:width="1000dp"
        android:height="50dp" /><!-- 宽度和高度 -->
    <!-- 间隔 -->
    <padding
        android:bottom="2dp"
        android:left="5dp"
        android:right="5dp"
        android:top="2dp" /><!-- 各方向的间隔 -->
    <!-- 圆角 -->
    <corners
        android:radius="90dp"
        android:topLeftRadius="20dp"
        android:topRightRadius="20dp"
        android:bottomLeftRadius="20dp"
        android:bottomRightRadius="20dp"/>
    <!-- 描边 -->
    <stroke
        android:width="2dp"
        android:color="@color/blue"
        android:dashWidth="0dp"
        android:dashGap="0dp"/><!-- dashWidth横线的宽度;dashGap表示之间隔开的距离 -->
</shape>

①shape

形状:rectangle、oval、line、ring。其中line、ring要通过stroke标签指定线的宽度和颜色)。

②corners

其中radius优先级最低。

③gradient

与solid标签互斥。
渐变效果填充。

属性:
–android:angle:
渐变的角度,默认为0,值应为45的倍数,0表示从左到右,90表示从下到上。
–android:centerX
渐变的中心点的坐标。
–android:startColor
渐变的起始色、中间色(centerColor)、结束色(endColor).
–android:gradientRadius
渐变半径,仅当android:type=”radial”时有效。
–android:useLevel
当Drawable作为StateListDrawable使用时为true.
–android:type
渐变类别。如:linear(线性渐变,默认)、radial(径向渐变)、sweep(扫描线渐变)

④solid

表示纯色填充。

⑤stroke

–android:width
描边的粗细。
–android:color
描边的颜色。
–android:dashWidth
描边组成虚线的线段的宽度。
–android:dashGap
描边虚线的线段之间的间隔。

⑥padding

表示包含drawable的View的空白

⑦size

shape的大小。通过该标签指定宽高后,getIntrinsicWidth就会返回该值,否则返回-1.

3)LayerDrawable

通过对应的XML<layer-list>,表示层次化的Drawable集合,通过将不同的Drawable放置在不同的层上面表达叠加后的效果。

举例一:
绘制图片背景,只保留顶部的边线。

<layer-list xmlns:android="http://schemas.android.com/apk/res/android">

    <item
        android:right="-5dp"
        android:left="-5dp"
        android:bottom="-5dp">
    <shape>
        <solid android:color="@android:color/transparent"/>
        <stroke
                android:width="5dp"
                android:color="@color/colorTheme"/>
        </shape>
    </item>
</layer-list>

举例二:文本输入框
文本输入框

4)StateListDrawable

对应<selector>标签,表示Drawable集合,每个Drawable都对应着View的一种状态。
主要用于可点击的View的背景。

举例:背景选择器

<?xml version="1.0" encoding="utf-8"?>  
<selector xmlns:android="http://schemas.android.com/apk/res/android"
    android:constantSize=["true"|"flase"]
    android:dither=["true"|"flase"]
    android:variablePadding=["true"|"flase"]>  

    <!-- 默认时的背景图片 -->  
    <item android:drawable="@drawable/btn_refresh"/>  

    <!-- 单击时的背景图片 -->  
    <item android:state_pressed="true" android:drawable="@drawable/btn_refresh_click" />  

    <!-- 程序是否在前台 -->  
    <item android:state_window_focused="false" android:drawable="@drawable/btn_refresh"/>  

    <!--选中时的图片背景-->    
    <item android:state_selected="true"   android:drawable="@drawable/btn_refresh" />     

    <!--获得焦点时的图片背景-->    
    <item android:state_focused="true"   android:drawable="@drawable/btn_refresh" />  

    <!-- 光标悬停 -->  
    <item android:state_hovered="true"  android:drawable="@drawable/btn_refresh" />  

    <!-- -->
    --android:state_checked  表示拥护选中了View,适用于CheckBox这类在选中和非选中状态之间进行切换的View.
    --android:state_enabled  表示当前处于可用状态
</selector> 

①constantSize

StateListDrawable的固有大小是否随着状态改变。true表示保持不变。默认为false.

②dither

是否开启抖动效果。
开启会让图片在低质量屏幕扔能显示。

③variablePadding

StateListDrawable是否随着其状态改变padding。true表示会随之改变。默认值为false。

④注意

是从上到下读取图片状态,如果把
<item android:drawable="@drawable/btn_refresh"/>
放在最前面,后面的可能不起作用。

⑤应用

CheckBox的背景图片/textColor设置为StateListDrawable可以进行点击切换动画。如下:

<item android:state_checked="true" android:drawable="@drawable/btn_click" />  
<item android:state_pressed="true" android:drawable="@drawable/btn_click" />  
<item android:state_checked="false" android:drawable="@drawable/btn_unclick" /> 
<item android:state_checked="true" android:color="@color/btn_click" />  
<item android:state_pressed="true" android:color="@color/btn_click" />  
<item android:state_checked="false" android:color="@color/btn_unclick" /> 

5)LevelListDrawable

LevelListDrawable对应于<level-list>标签,是一个Drawable集合,集合中每一个Drawable都有一个登记的概念。根据不同等级,切换对应的Drawable。

如下所示,每个item表示一个Drawable,对应其等级范围。

<?xml versionn="1.0" encoding="utf-8"?>
<level-list
    xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:drawable="@drawable/icon1"
        android:maxLevel="integer"
        android:minLevel="integer"/>
</level-list>

使用时,通过Drawable的setLevel方法设置不同等级(0~10000),切换Drawable。
或通过ImageView的setImageLevel方法来切换。

6)TransitionDrawable

对应于<transition>标签,用于实现两个Drawable之间的淡入淡出效果。

<?xml versionn="1.0" encoding="utf-8"?>
<transition
    xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:drawable="@drawable/icon1"
        android:id=""
        android:top="dimension"
        android:right="dimension"
        android:bottom="dimension"
        android:left="dimension"/>
</transition>

相应的View的background设置为此Drawable。
最后通过TransitionDrawable 的startTransition和reverseTransition方法来实现淡入淡出的效果以及你过程。

TextView textView = (TextView) findViewById(R.id.tv_transition);
TransitionDrawable drawable = (TransitionDrawable) textView.getBackground();
drawable.startTransition(1000);

7)InsetDrawable

对应于<inset>标签,用于一个View希望比自己的实际区域小的时候。LayerDrawable也可以实现这种效果。

<?xml versionn="1.0" encoding="utf-8"?>
<inset
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:insetTop="15dp"
    android:insetRight="15dp"
    android:insetBottom="15dp"
    android:insetLeft="15dpn">
    <shape android:shape="rectangle">
        <solid android:color="#ff0000"/>
    </shape>
</inset>
View v_scale = findViewById(R.id.scale);
ScaleDrawable sacleDrawable = (ScaleDrawable )v_scale.getBackground();
sacleDrawable setLevel(1);

8)ScaleDrawable

对应<scale>标签,根据等级(getLevel方法,范围为0-10000)指定Drawable缩放比例。
等级越大,表示裁剪的区域越小。
level=0,表示ScaleDrawable不可见(完全裁剪),这是默认值。
level=10000,不裁剪。

<?xml versionn="1.0" encoding="utf-8"?>
<scale
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="#drawable/icon1"
    android:scaleGravity=["top" | "bottom" | "left" | "right" | "center_vertical" | "fill_vertical" | "center" | "fill" | "clip_vertical"]
    android:scaleHeight="20%"
    android:scaleWidth="20%"/>

9)ClipDrawable

对应于<clip>标签,根据等级裁剪另一个Drawable。裁剪方向由android:clipOrientation和android:gravity控制。

<?xml versionn="1.0" encoding="utf-8"?>
<clip
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="#drawable/icon1"
    android:gravity=["top" | "bottom" | "left" | "right" | "center_vertical" | "fill_vertical" | "center" | "fill" | "clip_vertical"]
    android:clipOrientation=["horizontal" | "vertical"]/>

gravity属性中:
–top 将内部Drawable放在容器顶部。如果为竖直裁剪,从底部开始裁剪。
–center_vertical 如果为竖直裁剪,从上下同时开始裁剪。
–fill_vertical 填充容器,只有等级为0(不可见)的裁剪行为。

ImageView clip = (ImageView)findViewById(r.id.clip);
ClipDrawable clipDrawable = (ClipDrawable) clip.getDrawable();
clipDrawable.setLevel(5000);

3,自定义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){
        finnal Rect r = getBounds();//获得实际区域大小,一般和View尺寸相同
        float cx = r.exactCenterX();
        float cy = r.exactCenterY();
        canvas.drawCircle(cx,cy,Math.min(cx,cy),mPaint);
    }

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

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

    @Override
    public void getOpacity(){
        return PixelFormat.TRANSLUCENT;
    }
}

4,

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值