Drawable入门

Drawable

        一个drawable就是一个图形资源。使用起来就和使用一个具体的图片一样。但是也有几种特殊的。

常用方法

        setBounds():设置一个矩形区域,当Drawable.draw()被调用时该drawable便会被画到指定的区域中。

BitmapDrawable

        一张图片。

xml

<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
    android:src="@mipmap/bg"
    android:tileMode="repeat"
    />

        以bitmap为根结点,由src属性指定对应的图片资源。常用属性如下:

        tileMode:src的重复模式。repeat图片在x,y轴方向上不断重复;mirror图片在x,y轴上以镜像排列;clamp用图片的最外缘一圈像素填充剩余的地方。因此对于下面形式的图片,只要截取一个基本重复单元,将tileMode设置为repeat就可以实现。图片如下:


        alpha:图片的透明度。0完全透明

        antialias:图片是否搞锯齿

        dither:图片是否防抖动——不明白这个抖动是啥玩意,不过建议开启

        filter:图片是否过滤——不知道开启与不开启有啥区别,不过建议开启

        gravity:当图片尺寸小于显示的View的尺寸时,用于定位图片的显示位置。与常用的gravity属性差不多。

        mipMap:不懂,就按默认的设置为false即可。

BitmapDrawable

        <bitmap>对应的java类为BitmapDrawable。大部分方法都是由上面的属性想对应的,其余的常用方法为:

        setColorFilter():与Paint#setColorFilter()方法的作用是一样的。

NinePatchDrawable

        与BitmapDrawable类似,它代表了一个.9图片。

        xml属性:以nine-patch为根结点,其余属性与BitmapDrawable一样,只不过src需要一个.9的图片。如下:

<nine-patch xmlns:android="http://schemas.android.com/apk/res/android"
    android:src="@drawable/bg"
    android:tileMode="repeat"
    />

        其中的tileMode无效。

ScaleDrawable

        对应<scale>标签,将指定的drawable进行缩放。常用属性

        scaleGravity:与gravity类似,缩放后的drawable显示的位置。

        scaleWidth与scaleHeight:宽、高上的缩放比例。

        使用scaleDrawable有一点要注意:必须调用ScaleDrawable#setLevel(),并传入大于1的参数。原因如下:

    @Override
    public void draw(Canvas canvas) {//ScaleDrawable的draw()
        final Drawable d = getDrawable();
        if (d != null && d.getLevel() != 0) {
            d.draw(canvas);
        }
    }
        从draw()方法中可以看出,如果level==0的话,是不会进行绘制的,也就是不显示任何内容。而level默认的就是0,所以必须调用setLevel为level进行重新赋值。

xml示例如下:

<scale android:drawable="@mipmap/fengjing"
    android:scaleGravity="center_horizontal"
    android:scaleHeight="90%"
    android:scaleWidth="20%"
    xmlns:android="http://schemas.android.com/apk/res/android" />
对应的代码为:
        ImageView iv = (ImageView) findViewById(R.id.image);
        ScaleDrawable drawabl1e = (ScaleDrawable) iv.getDrawable();
        drawabl1e.setLevel(1);

TransitionDrawable

基础

       可以在两个drawable之间形成淡入淡出(cross-fade)效果。如同写布局一样,它的定义方式有两种:在xml文件中和通过代码生成(即使用TransitionDrawable类)。

       要注意的是:无论是通过xml还是代码,都必须调用TransitionDrawable.startTransition()才能有效果

xml中

在res/drawable目录下,建立一个xml。xml具体如下:

    <?xml version="1.0" encoding="utf-8"?>
    <transition
    xmlns:android="http://schemas.android.com/apk/res/android" >
        <item
            android:drawable="@[package:]drawable/drawable_resource"
            android:id="@[+][package:]id/resource_name"
            android:top="dimension"
            android:right="dimension"
            android:bottom="dimension"
            android:left="dimension" />
    </transition>
        其中根结点必须是transition。每一个<item>就代表着一个要加入到TransitionDrawable中的drawable。示例:
<?xml version="1.0" encoding="utf-8"?>
<transition xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/on" />
    <item android:drawable="@drawable/off" />
</transition>

相应的代码

ImageView iv = (ImageView) findViewById(R.id.listView1);
iv.setImageResource(R.drawable.t_drawable);//也可以直接在xml中设置
final TransitionDrawable drawable = (TransitionDrawable) iv
	.getDrawable();//获取相应的drawable
drawable.startTransition(1500);//开始
new Handler().postDelayed(new Runnable() {
	public void run() {
		drawable.reverseTransition(4000);
	}
}, 2000);

通过代码生成

示例如下:

Drawable[] layers = new Drawable[2];//定义图片资源
layers[0] = getResources().getDrawable(
		R.drawable.chatto_bg_voiceforward_focused);
layers[1] = getResources().getDrawable(
		R.drawable.friendactivity_remind_normal);
final TransitionDrawable drawable = new TransitionDrawable(layers);//生成相应的drawable
ImageView iv = (ImageView) findViewById(R.id.listView1);
iv.setImageDrawable(drawable);//设置到对应的imageview中
drawable.startTransition(1500);//开始
new Handler().postDelayed(new Runnable() {
	public void run() {	
	drawable.reverseTransition(4000);
	}
}, 2000);

方法

        startTransition(int durationMillis):开始执行淡入淡出的动画,此时第一张淡出,第二张淡入。

        reverseTransition(int duration):从当前状态往回显示。开始时第一张淡入,第二张淡出。但如果执行该方法时第一张已经完全显示,就类似startTransition(),第一张淡出,第二张淡入。

LayerDrawable

理解

       它控制着一系列的drawable,里面的drawable是按层分布的,类似于Framelayout。最后的一个drawable出现在最上面。最常见的例子便是ProgressBar(分了三层)。

xml中

        在res/drawable目录下,建立一个xml。xml具体格式同上面类似,只不过把根结点为<layer-list>。示例:

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
    <item>
        <bitmap
            android:gravity="center"
            android:src="@drawable/red" />
    </item>
    <item
        android:left="10dp"
        android:top="10dp">
        <bitmap
            android:gravity="center"
            android:src="@drawable/blue" />
    </item>
    <item
        android:left="20dp"
        android:top="20dp">
        <bitmap
            android:gravity="center"
            android:src="@drawable/green" />
    </item>
</layer-list>

        其中的top,left,bottom,right等属性表示Drawable相对于整个View的偏移量。

        在上面,并没有直接在<item>中通过drawable引用相应的图片,这是因为直接引用时,这些图片会被缩放去适应整个容器为避免这个情况才在<item>下使用了<bitmap>。效果图如下:

其中上面一张是没有使用<bitmap>结点的,下面一张是使用<bitmap>结点的。

LevelListDrawable

        xml对应的是<level-list>根结点。其类似于LayerDrawable,但LayerDrawable会将所有的Drawable分层,显示时会全部显示。但LevelListDrawable只会根据当前指定的level显示出指定level上的图片。某一drawable所处的level,可以通过maxLevel和minLevel指定一个范围。如下:

<level-list xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <item
        android:drawable="@mipmap/baidu"
        android:maxLevel="10"
        android:minLevel="8" />
    <item
        android:drawable="@mipmap/fengjing"
        android:maxLevel="6"
        android:minLevel="2" />
</level-list>
对应的java代码为:
        ImageView iv = (ImageView) findViewById(R.id.image);
        iv.setImageLevel(5);//通过该方法指定当前ImageView要显示的层
        ImageView imageView = (ImageView) findViewById(R.id.image2);
        LevelListDrawable drawable = new LevelListDrawable();
        drawable.addLevel(2,6, ContextCompat.getDrawable(this,R.mipmap.fengjing));
        drawable.addLevel(8,10, ContextCompat.getDrawable(this,R.mipmap.baidu));
        imageView.setImageDrawable(drawable);
        imageView.setImageLevel(9);
效果图为


        上面的是通过xml文件加载的,下面的是通过代码指定的。从中可以看出,并没有显示所有的drawable,只是根据level层,显示了当前层指定的drawable。

StateListDrawable

       状态选择器,根结点就是selector。当状态改变时,一系列的图片会重新遍历一遍,只要有一个满足当前状态的,就会停止遍历,并采用当前的图片。但是,这个满足当前状态的并不一定是最合适的。也就是说它只求满足,并不求最适合。

       参考:http://blog.csdn.net/leasystu/article/details/7250885

状态说明:

        android:state_selected:被选中。有可能是通过方向键进行选中的,并不一定具有焦点。

        android:state_checkable:是否可选。

        android:state_checked:是否选中。

        android:state_enabled:是否可用。

        android:state_window_focused:当前窗口是否具有焦点。如:notification被拉下来或者dialog显示的时候,该窗口就没有焦点。

ShapeDrawable

        对应res/drawable的shape标签。有一点要注意:该drawable必须设置bounds,如果不设置便不会绘制内部的shape。

        它能绘制一些原始的简单的图形,一个ShapeObject内部含有一个Shape对象(默认是RectShape),并且控制着Shape在屏幕上的显示。如

//一个黄色宽度为2的圆环
public class CustomShapeDrawable extends View {
    private ShapeDrawable drawable;
    public CustomShapeDrawable(Context context) {
        this(context, null);
    }
    public CustomShapeDrawable(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }
    public CustomShapeDrawable(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }
    private void init() {
        int x = 10, y = 10;
        drawable = new ShapeDrawable(new OvalShape());//Oval为椭圆形
        Paint paint = drawable.getPaint();//通过获取的paint可以设置绘画的形状
        paint.setColor(Color.YELLOW);
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeWidth(2);
        drawable.setBounds(x, y, x + 100, y + 100);//设置shape绘制的位置
    }
    @Override
    protected void onDraw(Canvas canvas) {
        drawable.draw(canvas);//调用drawable的draw方法进行绘制
    }
}

ClipDrawable

        截取指定drawable的某些区域进行显示xml中根结点是clip
        其中gravity指的是裁剪的起始位置,level指的是裁剪后该drawable剩余的部分,0表示完全裁剪,10000表示不裁剪。
        如果为水平裁剪,则根据gravity指定的位置开始。如果gravity指定的是垂直方向的位置,则从水平中心开始;垂直方向亦然。
        通过setLevel()来指定要截取的区域的大小,0最小,10000表示全部。它还需要指定一个方向,水平或者垂直,水平时drawable的高度完全显示,类似于卷轴水平打开时;垂直时就类似于卷轴竖起打开。可以使用它来做一个进度条。示例如下:
clip_test.xml
<clip xmlns:android="http://schemas.android.com/apk/res/android"
    android:clipOrientation="horizontal"
    android:drawable="@drawable/fengjing1114"
    android:gravity="left" >
</clip>
对应的activity中的代码:
//该imageview已经设置了android:src="@drawable/clip_test"
ImageView iv = (ImageView) findViewById(R.id.iv);
clipDrawable = (ClipDrawable) iv.getDrawable();
final Timer timer = new Timer();
timer.schedule(new TimerTask() {
	public void run() {
		if (mLevel >= 10000) {
			timer.cancel();
			return;
		}
		mLevel += 201;
		mLevel = Math.min(mLevel, 10000);
		System.out.println("mlevel = " + mLevel);
		runOnUiThread(new Runnable() {
			public void run() {
				clipDrawable.setLevel(mLevel);
			}
		});
	}
}, 0, 100);

InsetDrawable

        将一个drawable嵌入到另一张drawable中,根结点是inset。在嵌入的过程中,可以设置内部drawable与外围drawable之前的距离。具体示例如下,其中insetXXX属性就是设置距离的,并且这些属性还可以设置成负数,此时图片就会自动地将负数对应的部分给截掉。
<?xml version="1.0" encoding="utf-8"?>
<inset xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/fengjing1114"
    android:insetBottom="6dp"
    android:insetLeft="3dp"
    android:insetRight="5dp"
    android:insetTop="4dp" >

</inset>
效果为:

应用

阴影效果

        结合layer-list与InsetDrawable可以仿造成阴影效果。主要思路是:通过InsetDrawable构建一个留有边框的drawable,再在该drawable底层放一个渐变的drawable即可。为实现在底层放一个drawable,就需要用layer-list。效果图为:


主要的XML代码如下:
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >

    <!-- 在底部画一个渐变的drawable,充当背景 -->
    <item>
        <shape android:shape="rectangle" >
            <corners android:radius="4dp" />

            <gradient
                android:angle="90"
                android:centerColor="#ee000000"
                android:centerY="0.05"
                android:endColor="#000000"
                android:startColor="#00000000" />
        </shape>
    </item>
    <!-- 这个item才是要显示的drawable -->
    <item>
        <inset
            android:drawable="@drawable/shape_bg"
            android:insetBottom="5dp" />
    </item>

</layer-list>
        直接在布局中引用该drawable即可。这样做只能实现单边的阴影效果,如果想要多边的,直接用图片吧。



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值