27
2017
09

Android开发艺术探索_Android的Drawable(六)

简介

表示一个中图像的概念,但又不完全表示图片,通过颜色也可以构造出各式各样的图像的效果;
一般作为控件的背景使用;
Drawable是一个抽象类,是所有Drawable对象的基类,每个具体的drawable都是他的子类;
可以通过getIntrinsicWidth/Height获取Drawable内部的宽高,但不是所有的Drawable都有宽高,
对于图片来来说他的内部宽高就是图片的宽高,但对颜色drawable来说是没有内部宽高这个概念的;
创建方式,在android视图下,as中,选中res文件夹,右键new resourcefile,类型选择为drawable

分类

BitmapDrawable

最简单的drawable,表示一张图片,可以通过直接引用图片,也可以通过xml的方式来设置更多的效果
<?xml version="1.0" encoding="utf-8"?>
<bitmap / nine-patch
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:src="@[package:]drawable/drawable_resource"
    android:antialias=["true" | "false"]
    android:dither=["true" | "false"]
    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:tileMode=["disabled" | "clamp" | "repeat" | "mirror"] />
src,图片的资源id
antialias,抗锯齿
dither,开启后可以让那个高质量的图片在低质量的屏幕上还能保持较好的显示效果
filter,开启过滤效果,当图片尺寸被拉伸或者压缩的时候,开启过滤效果可以保持比较好的显示显示效果
gravity,当图pain小于容器的尺寸时,可以控制图片的位置
    top,bottom,left,right:表示图片放置在容器的位置,不改变图片的大小
    center_vertical,center_horizontal,center:居中的模式,不改变图片的大小
    fill_vertical,fill_horizontal,fill:图片拉伸的模式
    clip_vertical,clip_hozizontal:表示裁剪的方向
titlemode,平铺模式,开启后会关闭gravity,
    repeat:简单的水平和竖直上的平铺效果
    mirror:镜面的平铺效果
    clamp:四周的像素会扩展都周围
    disable:关闭平铺模式

ShapeDrawable

可以理解为通过颜色来构造的图,可以是纯色也可以是渐变
<?xml version="1.0" encoding="utf-8"?>
<shape    
    xmlns:android="http://schemas.android.com/apk/res/android"    
    android:shape=["rectangle" | "oval" | "line" | "ring"] >    
    <corners        //当shape为rectangle时使用
        android:radius="integer"        //半径值会被后面的单个半径属性覆盖,默认为1dp
        android:topLeftRadius="integer"        
        android:topRightRadius="integer"        
        android:bottomLeftRadius="integer"        
        android:bottomRightRadius="integer" />    
    <gradient       //渐变
        android:angle="integer"        
        android:centerX="integer"        
        android:centerY="integer"        
        android:centerColor="integer"        
        android:endColor="color"        
        android:gradientRadius="integer"        
        android:startColor="color"        
        android:type=["linear" | "radial" | "sweep"]        
        android:useLevel=["true" | "false"] />    
    <padding        //内边距
        android:left="integer"        
        android:top="integer"        
        android:right="integer"        
        android:bottom="integer" />    
    <size           //指定大小,一般用在imageview配合scaleType属性使用
        android:width="integer"        
        android:height="integer" />    
    <solid          //填充颜色
        android:color="color" />    
    <stroke         //边框
        android:width="integer"        
        android:color="color"        
        android:dashWidth="integer"        
        android:dashGap="integer" />
</shape>

根标签

shape:
    rectanele矩形

    oval椭圆

    line横线,必须通过<stroke>标签来指定线的宽度.

    ring圆环,必须通过<stroke>标签来指定线的宽度.
    innerRadius,内部圆的半径
    thickness,圆环的厚度
    innerRadiusRatio,内部半与整个Drawable宽度的比例,与innerRadius冲突,优先级低于innerRadius.
    thicknessRatio,厚度占整个Drawable宽度的比例,默认为3,与thickness冲突,优先级低于thickness.
    useLevel,一般为false,在LevelListDrawable时使用

item

corners,表示四个角的角度.只在rectangle中使用.
    radius,四个角的角度,优先级低
    topLeftRadius,topRightRadius,bottomLeftRadius,bottomRightRadius,表示四个角的圆角圆半径.

gradient,渐变填充效果,与solid相冲突
    angle,渐变的角度,默认为0,必须为45的倍数,0表示从左到右,90表示从上到下
    centerX,centerY渐变的中心的坐标
    startColor,centerColor,endColor,不同位置的渐变色
    type,渐变模式,linear radial sweep
    gradientRadius,渐变半径,只有type=radial时有效
    useLevel,一般为false,在LevelListDrawable时使用

solid,纯色填充,与    gradient冲突
    color,填充的颜色

stroke,shape的边界
    width,边界的宽度
    color,边界的颜色
    dashWidth,组成虚线的宽度
    dashGash,组成虚线间的线段之间的间隔

padding,包含它的view的空间
    left,top,right,bottom

size,shape的大小
    width height,表示shape的固有大小,但不是最终显示的大小.因为对shape来说并没有宽高的概念.
    一般来说,shape的Drawable对象getIntrinsicWidth getIntrinsicHeight会返回-1,有了这个属性后便
    会返回设置的大小.

LayerDrawable

对应的标签为<layer-list>,表示一种层次化的Drawable集合,通过将不同的层上面的从而达到一种叠加后的效果.
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="" android:id="@resId" android:top android:right android:bottom android:left/>
          //嵌套shape
          <shape/>
    </item>
</layer-list>    
创建顶部是蓝色线条的Drawale
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">

    <!--底层使用蓝色填充色-->
    <item>
        <shape>
            <solid android:color="#02a0ef"/>
        </shape>
    </item>

    <!--上面一层距离底层的顶部1dp,距离底部1dp,类似marginTop,填充色为白色,这样就形成了一个带有蓝色顶部边线和底部边线的白色背景的图-->
    <item android:bottom="1dp" android:top="1dp">
        <shape>
            <solid android:color="#fff"/>
        </shape>
    </item>
</layer-list>

StateListDrawable

对应于<selector>标签,也表示drawable集合,每个drawable对应view的一种状态,系统会根据view的状态来选择合适的Drawable.
主要用于设置可单击的view背景

其顺序是,从上到下查找符合条件的drawable,找到后则return,所以默认效果一般放在最后
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" android:constantSize="true"//StateListDrawable的固有大小是否随着其状态的改变而改变 android:dither="true"//高清图片在低清晰度的是否优化显示效果 android:variablePadding="true"//padding是否随着其状态的改变而改变,不建议开启 android:visible="true">
    <item  android:drawable="@color/colorAccent" android:state_activated="true" android:state_checkable="true" android:state_checked="true"//选中效果,一般在checkedbox这类控件中使用 android:state_enabled="true"//是否可用 android:state_focused="true"//是否获取了焦点 android:state_hovered="true" android:state_pressed="true"//按下了但还没有松开的状态 android:state_selected="true"//选择 android:state_window_focused="true"/>
</selector>

LevelListDrawable

对应<level-list>标签,表示一个drawable集合,每个集合中有一个level的概念,根据不同的等级显示不同的drawable
<?xml version="1.0" encoding="utf-8"?>
<level-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item  android:drawable="@color/colorAccent" android:maxLevel="int" android:minLevel="int"/>
    <item..>    
</level-list>
每个item表示一个drawable,并且有对应的等级范围,范围为0-10000,默认值是0;
通过Drawable.setLevel来设置等级从而切换drawable
在iamgeview中使用时,可以通过setImageLevel来设置等级

TransitionDrawable

对应于<transition>,用于实现两个drawable之间的淡入淡出效果
<?xml version="1.0" encoding="utf-8"?>
<transition xmlns:android="http://schemas.android.com/apk/res/android">
    <item  android:drawable="@color/colorAccent" android:id="@resId" android:top="" android:right="" android:bottom="" android:left=""/>
</transition>
一般设置俩个item
TransitionDrawable drawable = (TransitionDrawable) v.getBackground();
drawable.startTransition(5000);
drawable.reverseTransition(5000);

InsetDrawable

对应标签<inset>,它可以将其他drawable内嵌到自己当中,并可以在四周留出一定的间距。当一个view希望自己的背景比自己的实际区域小的时候,可以采用InsetDrawable来实现。
<inset xmlns:android="http://schemas.android.com/apk/res/android" android:insetBottom="15dp"//底部内凹的大小,shape距离边界的距离(dp) android:insetLeft="15dp" android:insetRight="15dp" android:insetTop="15dp" >

    <shape android:shape="rectangle" >
        <solid android:color="#ff0000" />
    </shape>

</inset>

ScaleDrawable

对应scale标签,可以根据自己的level来将指定的drawable缩放到一定的比例
//将一张图片缩小为30%,是的,没错,下面的代码将图片缩小为原来的30%
<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android" android:drawable="" android:scaleGravity="top|bottom|left|right|center |center_vertical|fill_vertical|center_horizontal|fill_hozizontal |center|fill|clip_vetical|clip_horizontal android:scaleHeight="70%" android:scaleWidth="70%">
</scale>
一定要执行代码,否则不为显示
View view=fvbi
(ScaleDrawable)view.getBackground().setLevel(1);//int 取值范围为0-10000;

源码中公式为:w-=(int)(w*(10000-level));

ClipDrawable

对应<clip>标签,可以自己当前的level来裁剪另一个drawable,裁剪方向由gravity和clipOrientation共同决定
<clip xmlns:android="http://schemas.android.com/apk/res/android" android:drawable="" android:clipOrientation="horizontal|vertical" android:gravity="bottom|top|left|right|center_vertical|fill_vertical |center_horizontal|fill_horizontal|center|fill|clip_horizontal|clip_vertical|">

</clip>
android:clipOrientation,
    horizontal,vertical,表示裁剪的方向

android:gravity,需要和cliporientation共同使用,可以通过|组合使用
    top,将图片放在容器的顶部,竖直裁剪则从底部开始裁剪
    bottom,将图片放在容器的底部,竖直裁剪则从顶部开始裁剪
    left,将图片放在容器的左部,竖直裁剪则从右边开始裁剪
    right,将图片放在容器的右边,竖直裁剪则从左边开始裁剪


    center_vertical,图片在容器中垂直居中,竖直裁剪从上下同时开始裁剪
    center_hozizontal,图片在容器中水平居中,水平裁剪从左右同时开始裁剪
    center,图片在容器中完全居中,竖直裁剪从上下同时开始裁剪,水平裁剪从左右同时开始裁剪

    fill_vertical,图片竖直填充,如果竖直裁剪,只有level为0的时候(0即完全被裁剪),才能有裁剪行为
    fill_hozizontal,图片水平填充,如果水平裁剪,只有level为0的时候(0即完全被裁剪),才能有裁剪行为
    fill,图片完全填充,只有level为0的时候(0即完全被裁剪),才能有裁剪行为

    clip_vertical,竖直方向的裁剪
    clip_horizontal,水平方向的裁剪
从上往下进行裁剪的效果
<clip xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@resId"
    android:clipOrientation="horizontal"
    android:gravity="bottom">
Imageview iv;
(ClipDrawable)iv.getDrawable();
clipDrawable.setLevel(5000);//0-10000;0表示完全裁剪,10000表示不裁剪

自定义Drawable

drawable的使用方法很单一,一是作为iamgeview中图像来显示,二是作为view的背景.
我们可以了解到view的工作原理,系统会调用Drawable的draw()来绘制view的背景,所以我们可以通过重写Drawable的draw()来实现自定义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(@NonNull Canvas canvas) {
        final Rect r=getBounds();
        float cx=r.exactCenterX();
        float cy=r.exactCenterY();
        canvas.drawCircle(cx,cy,Math.min(cx,cy),mPaint);
    }

    @Override
    public void setAlpha(@IntRange(from = 0, to = 255) int alpha) {
        mPaint.setAlpha(alpha);
        invalidateSelf();
    }

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

    @Override
    public int getOpacity() {
        return PixelFormat.TRANSLUCENT;
    }
    //最好重写获取固有宽高的方法,因为该Drawable是由颜色填充的所有没有重写
    @Override
    public int getIntrinsicHeight() {
        return super.getIntrinsicHeight();
    }

    @Override
    public int getIntrinsicWidth() {
        return super.getIntrinsicWidth();
    }
}
上一篇:Activity transition(Activity转场动画效果) 下一篇:DataBinding的基本使用