Android繪製圓形圖片的方法總結
在需求開發中經常會遇到需要顯示圓形圖片的情況,比如我們經常見到的使用者圓形頭像。為了實現這個效果,我們需要重新定義View,通過重寫onDraw方法來使得我們的View顯示成圓形。要是實現這個功能主要有三種方法。
使用Xfermode 相交模式
什麼是相交模式?正常的情況下,在已有的影象上繪圖將會在其上面新增一層新的形狀。如果新的Paint是完全不透明的,那麼它將完全遮擋住下面的Paint;如果它是部分透明的,那麼它將會被染上下面的顏色。而setXfermode就可以來解決這個問題,設定兩張圖相交之後的顯示模式。canvas原有的圖片可以理解為背景,就是dst;新畫上去的圖片可以理解為前景,就是src。下面是全部的16種相交模式的效果圖。
由上圖可以看到,如果我們需要畫一個圓形的圖,可以有幾種方法,比如,可以通過先繪製原圖,然後使用DstIn的方式繪製一個圓;或者可以先繪製一個圓,然後通過SrcIn的方式繪製原圖。我們使用第一種方法的程式碼如下:
@Override protected void onDraw(Canvas canvas) { Drawable drawable = getDrawable(); if (drawable != null) { //步驟1:先生成一個bitmap,在bitmap上繪製原圖 bitmap = Bitmap.createBitmap(getWidth(),getHeight(), Bitmap.Config.ARGB_8888); Canvas bitmapCanvas = new Canvas(bitmap); drawable.setBounds(0, 0, getWidth(), getHeight()); drawable.draw(bitmapCanvas); //步驟2:生成圓形圖片蒙版 Bitmap mask = Bitmap.createBitmap(width, height,Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(mask); Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); paint.setColor(Color.BLACK); canvas.drawOval(new RectF(0.0f, 0.0f, width, height), paint); //步驟3:使用DST_IN的方式在原圖的bitmap上繪製蒙版圖 mPaint.reset(); mPaint.setFilterBitmap(false); mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN)); bitmapCanvas.drawBitmap(mask, 0.0f, 0.0f, mPaint); //步驟4:將最後生成的這個bitmap繪製到View的canvas上 if (bitmap != null) { mPaint.setXfermode(null); canvas.drawBitmap(bitmap, 0.0f, 0.0f, mPaint); } } }
通過裁剪畫布區域實現
Canvas類提供了ClipPath, ClipRect, ClipRegion 等方法來裁剪畫布,通過他們的不同組合,可以得到任意形狀的畫布,然後在這個區域上畫圖,就可以獲得對應形狀的View了。但是,使用裁剪畫布的方式實現圓形頭像會有鋸齒,邊緣不如其他方式平滑。程式碼如下:
//為了保證繪製出來的View為圓形,如果圖片的長寬不一致,長的部分會被截斷 @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int mSize = Math.min(getMeasuredWidth(), getMeasuredHeight()); mRadius = mSize / 2; setMeasuredDimension(mSize, mSize); } @Override protected void onDraw(Canvas canvas) { mPath.addCircle(mRadius, mRadius, mRadius, Path.Direction.CW); canvas.clipPath(mPath); super.onDraw(canvas); }
使用BitmapShader
Shader就是畫筆Paint的渲染器,本質上這種方法其實是畫圓,只是渲染時採用了我們設定的圖片。
BitmapShader是Shader的子類,可以通過Paint.setShader(Shader shader)進行設定,然後用這個Paint繪圖時,就會根據你設定的TileMode,對繪製區域進行著色。BitmapShader的構造方法:
mBitmapShader = new BitmapShader(bitmap, TileMode.CLAMP, TileMode.CLAMP);
引數TileMode的取值有三種:
CLAMP 拉伸:拉伸的是圖片最後的那一個畫素
REPEAT 重複:就是橫向、縱向不斷重複這個bitmap
MIRROR 映象:橫向、縱向不斷翻轉重複
程式碼示例如下:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
mSize = Math.min(getMeasuredWidth(), getMeasuredHeight());
mRadius = mSize / 2;
setMeasuredDimension(mSize, mSize);
}
@Override
protected void onDraw(Canvas canvas) {
//得到原bitmap
Bitmap src = ((BitmapDrawable) getDrawable()).getBitmap();
if (src == null) {
super.onDraw(canvas);
return;
}
//把bitmap縮小為和View大小一致
Bitmap newBitmp = Bitmap.createScaledBitmap(src, mSize, mSize, false);
if (newBitmp == null) {
return;
}
//將縮小後的bitmap設定為畫筆的shader
mBitmapShader = new BitmapShader(newBitmp, Shader.TileMode.REPEAT,
Shader.TileMode.REPEAT);
//生成用來繪圖的bitmap,並在其上用畫筆繪圖
Bitmap dest = Bitmap.createBitmap(mSize, mSize, Bitmap.Config.ARGB_8888);
if (dest == null) {
return;
}
Canvas c = new Canvas(dest);
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setShader(mBitmapShader);
c.drawCircle(mRadius, mRadius, mRadius, paint);
//將最後生成的bitmap繪製到View的canvas上
canvas.drawBitmap(dest, 0, 0, paint);
}
上面這三種方法都可以實現圓形頭像,也可以實現其他形狀,通常第一種實現方式使用的比較多。