繼續(xù)基礎View的學習,這回到了頭像的處理
本次主要使用到的知識點是canvas.saveLayer:通過saveLayer()、new Canvas(bitmap)這些方法來人為新建一個畫布。尤其是saveLayer(),一旦調(diào)用saveLayer()新建一個畫布以后,以后的所有draw函數(shù)所畫的圖像都是畫在這個畫布上的,只有當調(diào)用restore()、resoreToCount()函數(shù)以后,才會返回到原始畫布上繪制。實際應該屬于圖像緩存區(qū),這個在以后再說。
先看下代碼實例:
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);
// 開始產(chǎn)生一個透明圖層,后續(xù)都在此透明圖層上繪制
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);
}
}
注釋了說的很清楚了,看下最終效果:

頭像示例
原始圖片是一個正方形的頭像,最終效果是被一個圓形切割成了圓頭像,接著又覆蓋在一個比它稍微大點的黑心園,所以還有個黑邊。