Android項(xiàng)目開發(fā)中經(jīng)常會(huì)遇見需要實(shí)現(xiàn)圓角或者圓形的圖片功能,如果僅僅使用系統(tǒng)自帶的ImageView控件顯然無(wú)法實(shí)現(xiàn)此功能,故通過(guò)系列文章的形式由簡(jiǎn)到繁全方位的介紹一下此功能的實(shí)現(xiàn),鞏固一下自身的學(xué)習(xí),同時(shí),和廣大網(wǎng)友交流分享。

作為第一篇文章,今天通過(guò)一些簡(jiǎn)單的代碼介紹一下圓形圖片功能的初步實(shí)現(xiàn)。
自定義的ImageView控件代碼如下,如果擁有一定的Android自定義View基礎(chǔ)知識(shí)的話,通過(guò)查看注釋基本上能夠看懂實(shí)現(xiàn)過(guò)程:
package com.feng.meiya.widget.imageview;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.widget.ImageView;
public class CircleImageView extends ImageView {
//基本的三個(gè)構(gòu)造函數(shù)
public CircleImageView(Context context) {
super(context);
}
public CircleImageView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CircleImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
//自定義View實(shí)現(xiàn)過(guò)程中很重要的onDraw繪制圖形的方法
@Override
protected void onDraw(Canvas canvas) {
Drawable drawable = getDrawable();
//空值判斷,必要步驟,避免由于沒(méi)有設(shè)置src導(dǎo)致的異常錯(cuò)誤
if (drawable == null) {
return;
}
//必要步驟,避免由于初始化之前導(dǎo)致的異常錯(cuò)誤
if (getWidth() == 0 || getHeight() == 0) {
return;
}
if (!(drawable instanceof BitmapDrawable)) {
return;
}
Bitmap b = ((BitmapDrawable) drawable).getBitmap();
if (null == b) {
return;
}
Bitmap bitmap = b.copy(Bitmap.Config.ARGB_8888, true);
int w = getWidth();
Bitmap roundBitmap = getCroppedBitmap(bitmap, w);
canvas.drawBitmap(roundBitmap, 0, 0, null);
}
/**
* 初始Bitmap對(duì)象的縮放裁剪過(guò)程
* @param bmp 初始Bitmap對(duì)象
* @param radius 圓形圖片直徑大小
* @return 返回一個(gè)圓形的縮放裁剪過(guò)后的Bitmap對(duì)象
*/
public static Bitmap getCroppedBitmap(Bitmap bmp, int radius) {
Bitmap sbmp;
//比較初始Bitmap寬高和給定的圓形直徑,判斷是否需要縮放裁剪Bitmap對(duì)象
if (bmp.getWidth() != radius || bmp.getHeight() != radius)
sbmp = Bitmap.createScaledBitmap(bmp, radius, radius, false);
else
sbmp = bmp;
Bitmap output = Bitmap.createBitmap(sbmp.getWidth(), sbmp.getHeight(),
Config.ARGB_8888);
Canvas canvas = new Canvas(output);
final Paint paint = new Paint();
final Rect rect = new Rect(0, 0, sbmp.getWidth(), sbmp.getHeight());
paint.setAntiAlias(true);
paint.setFilterBitmap(true);
paint.setDither(true);
canvas.drawARGB(0, 0, 0, 0);
paint.setColor(Color.parseColor("#BAB399"));
canvas.drawCircle(sbmp.getWidth() / 2 + 0.7f,
sbmp.getHeight() / 2 + 0.7f, sbmp.getWidth() / 2 + 0.1f, paint);
//核心部分,設(shè)置兩張圖片的相交模式,在這里就是上面繪制的Circle和下面繪制的Bitmap
paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
canvas.drawBitmap(sbmp, rect, rect, paint);
return output;
}
}
其中一個(gè)很重要的地方就是Paint.setXfermode(Xfermode xfermode)方法,設(shè)置兩圖的相交模式,這里只作簡(jiǎn)單的介紹:
系統(tǒng)提供的Xfermode子類有三個(gè):
AvoidXfermode
指定了一個(gè)顏色和容差,強(qiáng)制Paint避免在它上面繪圖(或者只在它上面繪圖)。PixelXorXfermode
當(dāng)覆蓋已有的顏色時(shí),應(yīng)用一個(gè)簡(jiǎn)單的像素XOR操作。PorterDuffXfermode
這是一個(gè)非常強(qiáng)大的轉(zhuǎn)換模式,使用它,可以使用圖像合成的16條Porter-Duff規(guī)則的任意一條來(lái)控制Paint如何與已有的Canvas圖像進(jìn)行交互。
常用用法如下:
Canvas canvas = new Canvas(bitmap1);
paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
canvas.drawBitmap(mask, 0f, 0f, paint);
可以簡(jiǎn)單理解為,canvas原有的圖片就是背景,即dst, 新畫上去的圖片就是前景,即src,這樣,不同的Mode展示效果如下:

看完上圖大致就能理解本文中自定義ImageView實(shí)現(xiàn)圓形圖片的原理了,下一篇將以GitHub中比較成熟的開源項(xiàng)目為例介紹一個(gè)功能全面、性能優(yōu)化的CircleImageView控件的實(shí)現(xiàn)過(guò)程,歡迎關(guān)注。
歡迎關(guān)注鳥哥微信公眾號(hào)【技術(shù)鳥】,掌握最新技術(shù)動(dòng)態(tài)!
