前言
在前面我们已经讲过,Drawable并不是图片,它只是一个抽象类,对要绘制什么,怎么绘制进行了封装
这篇博客,我们以一个实际的例子来具体阐述,Drawable是如何工作的
功能
功能非常简单,主要是为了演示Drawable如何工作
我们实现的是一个ImageView,它将图片的左半侧显示为灰色,右半侧显示为彩色
这个效果非常容易实现,这里我们主要是通过它来演示Drawable的工作原理
代码
package com.android.architecture;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import com.easing.commons.android.manager.Bitmaps;
//图像左侧变灰效果
@SuppressWarnings("all")
public class HalfGreyDrawable extends Drawable {
final Drawable baseDrawable;
final Bitmap baseBitmap;
//绘制灰色部分
final Paint paint1 = new Paint();
//绘制正常部分
final Paint paint2 = new Paint();
public HalfGreyDrawable(Drawable baseDrawable) {
this.baseDrawable = baseDrawable;
this.baseBitmap = Bitmaps.drawableToBitmap(baseDrawable);
ColorMatrix matrix = new ColorMatrix(new float[]{
0.333F, 0.333F, 0.333F, 0, 0,
0.333F, 0.333F, 0.333F, 0, 0,
0.333F, 0.333F, 0.333F, 0, 0,
0, 0, 0, 1, 0
});
ColorMatrixColorFilter filter = new ColorMatrixColorFilter(matrix);
paint1.setColorFilter(filter);
paint1.setAlpha(255);
}
//这里共实现了三个效果
//一个是图像的半侧变灰效果
//一个是变灰的位置带有动画效果,从左往右,再从右往左,如此反复
//一个是图像支持局部显示
@Override
public void draw(Canvas canvas) {
int level = getLevel();
Rect bounds = getBounds();
int w = bounds.right - bounds.left;
int h = bounds.bottom - bounds.top;
//绘制灰色部分
{
Rect srcRect = new Rect(bounds.left, bounds.top, bounds.left + w * level / 100, bounds.bottom);
Rect canvasBounds = canvas.getClipBounds();
int canvasW = canvasBounds.right - canvasBounds.left;
int canvasH = canvasBounds.bottom - canvasBounds.top;
Rect dstRect = new Rect(canvasBounds.left, canvasBounds.top, canvasBounds.left + canvasW * level / 100, canvasBounds.bottom);
canvas.drawBitmap(baseBitmap, srcRect, dstRect, paint1);
}
//绘制正常部分
{
Rect srcRect = new Rect(bounds.left + w * level / 100, bounds.top, bounds.right, bounds.bottom);
Rect canvasBounds = canvas.getClipBounds();
int canvasW = canvasBounds.right - canvasBounds.left;
int canvasH = canvasBounds.bottom - canvasBounds.top;
Rect dstRect = new Rect(canvasBounds.left + canvasW * level / 100, canvasBounds.top, canvasBounds.right, canvasBounds.bottom);
canvas.drawBitmap(baseBitmap, srcRect, dstRect, paint2);
}
}
@Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
}
@Override
public void setAlpha(int alpha) {
paint1.setAlpha(alpha);
}
//不允许设置自己的ColorFilter
@Override
public void setColorFilter(ColorFilter colorFilter) {
throw new RuntimeException("Unsupported Operation");
}
@Override
public int getIntrinsicWidth() {
return baseDrawable.getIntrinsicWidth();
}
@Override
public int getIntrinsicHeight() {
return baseDrawable.getIntrinsicHeight();
}
//当我们只想绘制Drawable的部分区域时
//Bounds可用来指示Drawable的绘制范围
@Override
protected void onBoundsChange(Rect bounds) {
super.onBoundsChange(bounds);
baseDrawable.setBounds(bounds);
invalidateSelf();
}
//对于有状态变化效果的Drawable
//Level可用于指示动画进度
//Level的范围为0-100,具体怎么用,是由用户自己来决定的
@Override
protected boolean onLevelChange(int level) {
invalidateSelf();
return true;
}
@Override
public void setBounds(int left, int top, int right, int bottom) {
super.setBounds(left, top, right, bottom);
baseDrawable.setBounds(left, top, right, bottom);
}
}
package com.android.architecture;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
@SuppressWarnings("all")
public class DrawableView extends View {
Drawable drawable;
//动画进度
int level = 0;
//动画方向
//先从左往右,到达最右侧,再从右往左
int positive = 1;
public DrawableView(Context context) {
this(context, null);
}
public DrawableView(Context context, AttributeSet attrs) {
super(context, attrs);
Drawable baseDrawable = context.getResources().getDrawable(R.drawable.gai_lun);
drawable = new HalfGreyDrawable(baseDrawable);
//只绘制整个图像中间80%的部分
//这里主要是为了演示Drawable.setBounds的作用
drawable.setBounds(
baseDrawable.getIntrinsicWidth() * 1 / 10,
baseDrawable.getIntrinsicHeight() * 1 / 10,
baseDrawable.getIntrinsicWidth() * 9 / 10,
baseDrawable.getIntrinsicHeight() * 9 / 10
);
//Drawable变化时,重新绘制View
//也可以不用Callback,直接invalidate
//这里主要是为了演示Drawable.invalidateSelf的刷新机制
drawable.setCallback(new Drawable.Callback() {
@Override
public void invalidateDrawable(Drawable d) {
invalidate();
}
@Override
public void scheduleDrawable(Drawable d, Runnable r, long t) {
}
@Override
public void unscheduleDrawable(Drawable d, Runnable r) {
}
});
}
@Override
protected void onDraw(Canvas canvas) {
//裁剪Canvas,只在右下角部分绘制
//这里主要是为了演示Canvas.clipRect的作用
Rect clipRect = new Rect();
Gravity.apply(
Gravity.RIGHT | Gravity.BOTTOM,
getMeasuredWidth() / 2,
getMeasuredHeight() / 2,
new Rect(0, 0, getMeasuredWidth(), getMeasuredHeight()),
clipRect
);
canvas.clipRect(clipRect);
//画HalfGreyDrawable
drawable.draw(canvas);
//增加Drawable动画效果
postDelayed(() -> {
level += positive;
if (level == 0)
positive = 1;
if (level == 100)
positive = -1;
drawable.setLevel(level);
}, 20);
}
}
源码下载
自定义Drawable.zip