继续基础View的学习,这回到了头像的处理
本次主要使用到的知识点是canvas.saveLayer:通过saveLayer()、new Canvas(bitmap)这些方法来人为新建一个画布。尤其是saveLayer(),一旦调用saveLayer()新建一个画布以后,以后的所有draw函数所画的图像都是画在这个画布上的,只有当调用restore()、resoreToCount()函数以后,才会返回到原始画布上绘制。实际应该属于图像缓存区,这个在以后再说。
先看下代码实例:
public class AvatarView extends View {
private static final float WIDTH = UiUtils.dpToPixel(250);
private static final float PADDING = UiUtils.dpToPixel(50);
private static final float EDGE = UiUtils.dpToPixel(15);
private Bitmap bitmap;
private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
PorterDuffXfermode mode;
RectF saveArea = new RectF();
public AvatarView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
{
bitmap = getAvatar((int) WIDTH);
mode = new PorterDuffXfermode(PorterDuff.Mode.SRC_IN);
saveArea.set(PADDING, PADDING, PADDING + WIDTH, PADDING + WIDTH);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// 先绘制一个大椭圆
canvas.drawOval(PADDING - EDGE, PADDING - EDGE,
PADDING + WIDTH + EDGE, PADDING + WIDTH + EDGE, paint);
// 开始产生一个透明图层,后续都在此透明图层上绘制
int saved = canvas.saveLayer(saveArea, paint);
// 在图层上绘制一个小一点的椭圆
canvas.drawOval(PADDING, PADDING, PADDING + WIDTH, PADDING + WIDTH, paint);
// 设置xfermode为SRC_IN,这样新的图,会被上一个椭圆切图
paint.setXfermode(mode);
// 绘制bitmap里的图片
canvas.drawBitmap(bitmap, PADDING, PADDING, paint);
// 重置paint的xfermode
paint.setXfermode(null);
// 重置canvas,并将透明图层绘制到最初界面
canvas.restoreToCount(saved);
}
Bitmap getAvatar(int width) {
BitmapFactory.Options options = new BitmapFactory.Options();
// 设为true后,decodeResource()只会取图片的宽高
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(getResources(), R.mipmap.name, options);
options.inJustDecodeBounds = false;
options.inDensity = options.outWidth;
options.inTargetDensity = width;
return BitmapFactory.decodeResource(getResources(), R.mipmap.name, options);
}
}
注释了说的很清楚了,看下最终效果:
头像示例
原始图片是一个正方形的头像,最终效果是被一个圆形切割成了圆头像,接着又覆盖在一个比它稍微大点的黑心园,所以还有个黑边。
网友评论