Android 自定义Drawable

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 自定义Drawable相关的知识,希望对你有一定的参考价值。

1.使用BitmapShader实现图片圆角

public class CornerDrawable extends Drawable {
    private Paint mPaint;
    private Bitmap bmp;
    private RectF rectF;

    public CornerDrawable(Bitmap bmp) {
        this.bmp = bmp;
        BitmapShader shader = new BitmapShader(bmp, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
//        CLAMP 拉伸
//        REPEAT 重复
//        MIRROR 镜像
//        BitmapShader是从画布的左上角开始绘制的
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setShader(shader);
    }

    @Override
    public void draw(Canvas canvas) {
        Rect rect = getBounds();
        // Log.e(getClass().getSimpleName(), rect.left + ":" + rect.width() + ":" + rect.height());
        // Log.e(getClass().getSimpleName(), rectF.left + ":" + rectF.width() + ":" + rectF.height());
        canvas.drawRoundRect(rectF, 20, 20, mPaint);
    }

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

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

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

    // getIntrinsicWidth、getIntrinsicHeight主要是为了在View使用wrap_content的时候,提供一下尺寸
    @Override
    public int getIntrinsicHeight() {
        return bmp.getHeight();
    }

    @Override
    public int getIntrinsicWidth() {
        return bmp.getWidth();
    }

    @Override
    public void setBounds(int left, int top, int right, int bottom) {
        super.setBounds(left, top, right, bottom);
        rectF = new RectF(left, top, right, bottom);
    }
}

2.除了圆角外,还可以指定画图片的某圆弧对应的内容

重写上面的draw方法如下

RectF rf = new RectF(-100, -130, 160, 130);
canvas.drawArc(rf, 0, 120, true, paint);

3.使用PorterDuffXfermode

    @Override
    public void draw(Canvas canvas) {
        PorterDuffXfermode pdf = new PorterDuffXfermode(PorterDuff.Mode.SRC_IN);
        paint.setXfermode(pdf);
        paint.setColor(0xffff4400);
        canvas.drawBitmap(bmp, 0, 0, paint);
        paint.setXfermode(null);
    }

》》XferMode

  1. AvoidXfermode  指定了一个颜色和容差,强制Paint避免在它上面绘图(或者只在它上面绘图)
  2. PixelXorXfermode  当覆盖已有的颜色时,应用一个简单的像素异或操作。
  3. PorterDuffXfermode  这是一个非常强大的转换模式,使用它,可以使用图像合成的16Porter-Duff规则的任意一条来控制Paint如何与已有的Canvas图像进行交互。

》》PorterDuff.Mode为枚举类,一共有16个枚举值:

  • PorterDuff.Mode.CLEAR    所绘制不会提交到画布上。
  • PorterDuff.Mode.SRC   显示上层绘制图片
  • PorterDuff.Mode.DST  显示下层绘制图片
  • PorterDuff.Mode.SRC_OVER  正常绘制显示,上下层绘制叠盖。
  • PorterDuff.Mode.DST_OVER  上下层都显示。下层居上显示。
  • PorterDuff.Mode.SRC_IN   取两层绘制交集。显示上层。
  • PorterDuff.Mode.DST_IN  取两层绘制交集。显示下层。
  • PorterDuff.Mode.SRC_OUT 取上层绘制非交集部分。
  • PorterDuff.Mode.DST_OUT 取下层绘制非交集部分。
  • PorterDuff.Mode.SRC_ATOP 取下层非交集部分与上层交集部分
  • PorterDuff.Mode.DST_ATOP 取上层非交集部分与下层交集部分
  • PorterDuff.Mode.XOR  异或:去除两图层交集部分
  • PorterDuff.Mode.DARKEN  取两图层全部区域,交集部分颜色加深
  • PorterDuff.Mode.LIGHTEN  取两图层全部,点亮交集部分颜色
  • PorterDuff.Mode.MULTIPLY  取两图层交集部分叠加后颜色
  • PorterDuff.Mode.SCREEN  取两图层全部区域,交集部分变为透明色

参考:ApiDemos/Graphics/XferModes

技术分享

 4.对图片进行颜色转换

    public static Drawable getPrimaryDrawable(int resId) {
        Drawable icon = context.getResources().getDrawable(resId);
        int baseColor = context.getResources().getColor(R.color._secondary_color);
        icon.setColorFilter(baseColor, PorterDuff.Mode.SRC_IN);
        return icon;
    }

5.通过xml定义drawable

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <shape>
            <solid android:color="#ff80cbc4" />
        </shape>
    </item>
    <item android:top="48dp">
        <bitmap
            android:gravity="center"
            android:src="@drawable/app_background_png"
            android:tileMode="disabled" />
    </item>
</layer-list>

6.自定义按钮状态

    <declare-styleable name="CustomStateDrawableButton">
        <attr name="state_readed" format="boolean" />
    </declare-styleable>

定义一个状态

public class CustomStateDrawableButton extends ImageButton {
    public static final int[] MessageReaded = {R.attr.state_readed};
    private boolean isReaded = false;

    public CustomStateDrawableButton(Context context) {
        super(context);
    }

    public CustomStateDrawableButton(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public CustomStateDrawableButton(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public void setReaded(boolean isReaded) {
        if (this.isReaded != isReaded) {
            this.isReaded = isReaded;
            //
            refreshDrawableState();
        }
    }

    @Override
    public int[] onCreateDrawableState(int extraSpace) {
        if (!isReaded) {
            int[] ds = super.onCreateDrawableState(extraSpace + 1);
            mergeDrawableStates(ds, MessageReaded);
            return ds;
        }
        return super.onCreateDrawableState(extraSpace);
    }
}

 

// http://www.devdiv.com/Android-Android%E4%B8%ADDrawable%E5%88%86%E7%B1%BB%E6%B1%87%E6%80%BB%EF%BC%88%E4%B8%8A%EF%BC%89-thread-126853-1-1.html
// ColorDrawable、GradientDrawable、BitmapDrawable、 NinePatchDrawable、InsetDrawable、ClipDrawable、ScaleDrawable、RotateDrawable、AnimationDrawable、LayerDrawable、LevelListDrawable、StateListDrawable、TransitionDrawable

以上是关于Android 自定义Drawable的主要内容,如果未能解决你的问题,请参考以下文章

Android自定义View之自定义drawable

Android 自定义Drawable

Android 应用开发中如何自定义 Drawable 背景?

Android实现一个自定义相机的界面

Seekbar进度drawable异常行为onPause

java 自定义Android ImageView,用于包含drawable的顶部裁剪。