Android 自定义圆形图片 CircleImageView
1.效果預覽
1.1.布局中寫自定義圓形圖片的路徑即可
?
1.2.然后看一看圖片效果
?
1.3.原圖是這樣的 @mipmap/ic_launcher
2.使用過程
2.1.CircleImageView源代碼
public class CircleImageView extends AppCompatImageView {private static final ScaleType SCALE_TYPE = ScaleType.CENTER_CROP;private static final Bitmap.Config BITMAP_CONFIG = Bitmap.Config.ARGB_8888;private static final int COLORDRAWABLE_DIMENSION = 1;private static final int DEFAULT_BORDER_WIDTH = 0;private static final int DEFAULT_BORDER_COLOR = Color.BLACK;private final RectF mDrawableRect = new RectF();private final RectF mBorderRect = new RectF();private final Matrix mShaderMatrix = new Matrix();private final Paint mBitmapPaint = new Paint();private final Paint mBorderPaint = new Paint();private int mBorderColor = DEFAULT_BORDER_COLOR;private int mBorderWidth = DEFAULT_BORDER_WIDTH;private Bitmap mBitmap;private BitmapShader mBitmapShader;private int mBitmapWidth;private int mBitmapHeight;private float mDrawableRadius;private float mBorderRadius;private boolean mReady;private boolean mSetupPending;public CircleImageView(Context context) {super(context);}public CircleImageView(Context context, AttributeSet attrs) {this(context, attrs, 0);}public CircleImageView(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);super.setScaleType(SCALE_TYPE);TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CircleImageView, defStyle, 0);mBorderWidth = a.getDimensionPixelSize(R.styleable.CircleImageView_border_width, DEFAULT_BORDER_WIDTH);mBorderColor = a.getColor(R.styleable.CircleImageView_border_color, DEFAULT_BORDER_COLOR);a.recycle();mReady = true;if (mSetupPending) {setup();mSetupPending = false;}}@Overridepublic ScaleType getScaleType() {return SCALE_TYPE;}@Overridepublic void setScaleType(ScaleType scaleType) {if (scaleType != SCALE_TYPE) {throw new IllegalArgumentException(String.format("ScaleType %s not supported.", scaleType));}}@Overrideprotected void onDraw(Canvas canvas) {if (getDrawable() == null) {return;}canvas.drawCircle(getWidth() / 2, getHeight() / 2, mDrawableRadius, mBitmapPaint);canvas.drawCircle(getWidth() / 2, getHeight() / 2, mBorderRadius, mBorderPaint);}@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);setup();}public int getBorderColor() {return mBorderColor;}public void setBorderColor(int borderColor) {if (borderColor == mBorderColor) {return;}mBorderColor = borderColor;mBorderPaint.setColor(mBorderColor);invalidate();}public int getBorderWidth() {return mBorderWidth;}public void setBorderWidth(int borderWidth) {if (borderWidth == mBorderWidth) {return;}mBorderWidth = borderWidth;setup();}@Overridepublic void setImageBitmap(Bitmap bm) {super.setImageBitmap(bm);mBitmap = bm;setup();}@Overridepublic void setImageDrawable(Drawable drawable) {super.setImageDrawable(drawable);mBitmap = getBitmapFromDrawable(drawable);setup();}@Overridepublic void setImageResource(int resId) {super.setImageResource(resId);mBitmap = getBitmapFromDrawable(getDrawable());setup();}private Bitmap getBitmapFromDrawable(Drawable drawable) {if (drawable == null) {return null;}if (drawable instanceof BitmapDrawable) {return ((BitmapDrawable) drawable).getBitmap();}try {Bitmap bitmap;if (drawable instanceof ColorDrawable) {bitmap = Bitmap.createBitmap(COLORDRAWABLE_DIMENSION, COLORDRAWABLE_DIMENSION, BITMAP_CONFIG);} else {bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), BITMAP_CONFIG);}Canvas canvas = new Canvas(bitmap);drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());drawable.draw(canvas);return bitmap;} catch (OutOfMemoryError e) {return null;}}private void setup() {if (!mReady) {mSetupPending = true;return;}if (mBitmap == null) {return;}mBitmapShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);mBitmapPaint.setAntiAlias(true);mBitmapPaint.setShader(mBitmapShader);mBorderPaint.setStyle(Paint.Style.STROKE);mBorderPaint.setAntiAlias(true);mBorderPaint.setColor(mBorderColor);mBorderPaint.setStrokeWidth(mBorderWidth);mBitmapHeight = mBitmap.getHeight();mBitmapWidth = mBitmap.getWidth();mBorderRect.set(0, 0, getWidth(), getHeight());mBorderRadius = Math.min((mBorderRect.height() - mBorderWidth) / 2, (mBorderRect.width() - mBorderWidth) / 2);mDrawableRect.set(mBorderWidth, mBorderWidth, mBorderRect.width() - mBorderWidth, mBorderRect.height() - mBorderWidth);mDrawableRadius = Math.min(mDrawableRect.height() / 2, mDrawableRect.width() / 2);updateShaderMatrix();invalidate();}private void updateShaderMatrix() {float scale;float dx = 0;float dy = 0;mShaderMatrix.set(null);if (mBitmapWidth * mDrawableRect.height() > mDrawableRect.width() * mBitmapHeight) {scale = mDrawableRect.height() / mBitmapHeight;dx = (mDrawableRect.width() - mBitmapWidth * scale) * 0.5f;} else {scale = mDrawableRect.width() / mBitmapWidth;dy = (mDrawableRect.height() - mBitmapHeight * scale) * 0.5f;}mShaderMatrix.setScale(scale, scale);mShaderMatrix.postTranslate((int) (dx + 0.5f) + mBorderWidth, (int) (dy + 0.5f) + mBorderWidth);mBitmapShader.setLocalMatrix(mShaderMatrix);}}View Code
?
2.2.在values中新建一個資源文件==>attrs_CircleImageView.xml
<resources><!-- 圓形頭像 --><declare-styleable name="CircleImageView"><attr name="border_width" format="dimension" /><attr name="border_color" format="color" /></declare-styleable></resources>View Code
?
2.3.布局中將ImageView視圖換成自定義類,路徑寫自己的
?
2.4.大功告成!然后圖片就乖乖地變成圓形了。如果想了解源碼,請看下方的分析。
3.CircleImageView源代碼分析
3.1.成員變量分析
ScaleType是圖片顯示方式。可以參考一下這篇文章了解ScaleType。
可以有八種取值方式:
①.matrix==>表示原圖從ImageView的左上角開始繪制。
②.fitXY==>填充整個ImageView,需要對圖片進行一些縮放,會變形。
③.fitStart==>按比例縮放至View的寬度或者高度(取最小值),然后居上或者居左顯示。
④.fitCenter==>將圖片按比例縮放之后居中顯示。
⑤.fitEnd==>按比例縮放之后居右或者居下顯示。
⑥.center==>將原圖按照原來的大小居中顯示,如果超出ImageView的大小,剪裁掉多余的部分。
⑦.centerCrop==>將ImageView填充滿,按照比例縮放原圖,多余的寬和高裁剪掉,最常用的。
⑧.centerInside==>將原圖完整的顯示出來,按照比例縮放原圖,一般都變得很小了。
?
Bitmap.Config是什么東西呢?可以參考一下這篇文章了解Bitmap.Config。
其實這都是色彩的存儲方法,我們知道ARGB指的是一種色彩模式。
里面A代表Alpha,R表示Red,G表示Green,B表示Blue。每個原色都存儲著所表示的顏色的信息值。
位圖位數越高代表其可以存儲的顏色信息越多,當然圖像也就越逼真。
?
這里定義了一個COLORDEAWABLE_DIMESION用來干什么呢?
?
然后又定義了一個DEFAULT_BORDER_WIDTH,用來干啥呢?
首先了解一下TypedArray,參考一下這篇文章。
首先需要有一個資源文件,就是自定義的視圖布局,這里是attrs_CircleImageView.xml
? ? 然后這里用到了DEFAULT_BORDER_WIDTH了。
?
了解一下RectF,參考一下這篇文章了解RectF。
RectF類和Rect類似,但是RectF參數是傳的Float,所以尾巴有個F了。
?
可以參考一下這篇文章了解Matrix。
這其實就是一個三維矩陣。
?
然后主要作用分成4塊。
? 用到的方法有:
?
postTranslate是指在setScale后平移。
由于縮放是以(0,0)為中心,所以為了把界面的中心與(0,0)對齊,調用postTranslate(centerX,centerY)把
圖片向這(x,y)方向移動。
?
什么是Paint類呢?參考這篇文章詳細了解。
這個類可以畫集合圖形,文本和Bitmap。
什么是BitmapShader呢?參考這篇文章詳細了解。
就是處理圖片渲染的。可以做到這樣的效果。
?
然后定義了兩個整型數據,兩個浮點型,兩個boolean型,之后再分析作用。
?
3.2.構造函數分析
一個參數的構造函數
?
兩個參數的構造函數
?
三個參數的構造函數
這個是最關鍵的一個構造函數了。
將資源文件中的寬度和顏色獲取到。
然后調用setup()函數進行初始化。
?
3.3.重寫函數getScaleType
3.4.重寫函數setScaleType
?
3.5.重寫onDraw
這里用canvas畫了兩個圓。
android中對于Canvas.drawCircle()方法不理解的可以參考這篇文章。
?
3.6.重寫onSizeChanged
?
3.7.邊界顏色
?
3.8.邊界寬度
調用了自己寫的一個setup()函數。
?
3.9.重寫setImageBitmap
調用了自己寫的一個setup()函數。?
?
3.10.重寫setImageDrawable
調用了自己寫的一個setup()函數。
?
3.11.重寫setImageResource
調用了自己寫的一個setup()函數。
?
3.12.將Drawable轉換成Bitmap
?
3.13.自己寫的setup函數
?
3.14.更新渲染
4.其他自定義圓形圖片
4.1.Android開發(fā)之自定義圓形的ImageView的實現
效果如下:
自定類代碼如下:
/*** 自定義的圓形ImageView,可以直接當組件在布局中使用。* @author caizhiming**/ public class XCRoundImageView extends ImageView{private Paint paint ;public XCRoundImageView(Context context) { this(context,null); } public XCRoundImageView(Context context, AttributeSet attrs) { this(context, attrs,0); } public XCRoundImageView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); paint = new Paint();} /*** 繪制圓形圖片* @author caizhiming*/@Override protected void onDraw(Canvas canvas) { Drawable drawable = getDrawable(); if (null != drawable) { Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap(); Bitmap b = getCircleBitmap(bitmap, 14); final Rect rectSrc = new Rect(0, 0, b.getWidth(), b.getHeight()); final Rect rectDest = new Rect(0,0,getWidth(),getHeight());paint.reset(); canvas.drawBitmap(b, rectSrc, rectDest, paint); } else { super.onDraw(canvas); } } /*** 獲取圓形圖片方法* @param bitmap* @param pixels* @return Bitmap* @author caizhiming*/private Bitmap getCircleBitmap(Bitmap bitmap, int pixels) { Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Config.ARGB_8888); Canvas canvas = new Canvas(output); final int color = 0xff424242;final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight()); paint.setAntiAlias(true); canvas.drawARGB(0, 0, 0, 0); paint.setColor(color); int x = bitmap.getWidth(); canvas.drawCircle(x / 2, x / 2, x / 2, paint); paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN)); canvas.drawBitmap(bitmap, rect, rect, paint); return output; } }View Code
?
4.2.第三方庫圓形頭像CircleImageView的使用
效果如下:
用法如下:
?
4.3.自定義ImageView系列——簡單圓形圖片
效果如下:
源代碼:
public class CircleImageView extends ImageView {//基本的三個構造函數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實現過程中很重要的onDraw繪制圖形的方法 @Overrideprotected void onDraw(Canvas canvas) {Drawable drawable = getDrawable();//空值判斷,必要步驟,避免由于沒有設置src導致的異常錯誤if (drawable == null) {return;}//必要步驟,避免由于初始化之前導致的異常錯誤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對象的縮放裁剪過程* @param bmp 初始Bitmap對象* @param radius 圓形圖片直徑大小* @return 返回一個圓形的縮放裁剪過后的Bitmap對象*/public static Bitmap getCroppedBitmap(Bitmap bmp, int radius) {Bitmap sbmp;//比較初始Bitmap寬高和給定的圓形直徑,判斷是否需要縮放裁剪Bitmap對象if (bmp.getWidth() != radius || bmp.getHeight() != radius)sbmp = Bitmap.createScaledBitmap(bmp, radius, radius, false);elsesbmp = 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);//核心部分,設置兩張圖片的相交模式,在這里就是上面繪制的Circle和下面繪制的Bitmappaint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));canvas.drawBitmap(sbmp, rect, rect, paint);return output;}}View Code
轉載于:https://www.cnblogs.com/Jason-Jan/p/7919311.html
總結
以上是生活随笔為你收集整理的Android 自定义圆形图片 CircleImageView的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: git cherry-pick. 如何把
- 下一篇: mvc手把手教你写excel导入