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; } } @Override public ScaleType getScaleType() { return SCALE_TYPE; } @Override public void setScaleType(ScaleType scaleType) { if (scaleType != SCALE_TYPE) { throw new IllegalArgumentException(String.format("ScaleType %s not supported.", scaleType)); } } @Override protected void onDraw(Canvas canvas) { if (getDrawable() == null) { return; } canvas.drawCircle(getWidth() / 2, getHeight() / 2, mDrawableRadius, mBitmapPaint); canvas.drawCircle(getWidth() / 2, getHeight() / 2, mBorderRadius, mBorderPaint); } @Override protected 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(); } @Override public void setImageBitmap(Bitmap bm) { super.setImageBitmap(bm); mBitmap = bm; setup(); } @Override public void setImageDrawable(Drawable drawable) { super.setImageDrawable(drawable); mBitmap = getBitmapFromDrawable(drawable); setup(); } @Override public 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); } }
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>
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,用来干啥呢?
首先需要有一个资源文件,就是自定义的视图布局,这里是attrs_CircleImageView.xml
然后这里用到了DEFAULT_BORDER_WIDTH了。
RectF类和Rect类似,但是RectF参数是传的Float,所以尾巴有个F了。
这其实就是一个三维矩阵。
然后主要作用分成4块。
用到的方法有:
postTranslate是指在setScale后平移。
由于缩放是以(0,0)为中心,所以为了把界面的中心与(0,0)对齐,调用postTranslate(centerX,centerY)把
图片向这(x,y)方向移动。
这个类可以画集合图形,文本和Bitmap。
就是处理图片渲染的。可以做到这样的效果。
然后定义了两个整型数据,两个浮点型,两个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开发之自定义圆形的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; } }
4.2.第三方库圆形头像CircleImageView的使用
效果如下:
用法如下:
效果如下:
源代码:
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绘制图形的方法 @Override protected 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); 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); //核心部分,设置两张图片的相交模式,在这里就是上面绘制的Circle和下面绘制的Bitmap paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN)); canvas.drawBitmap(sbmp, rect, rect, paint); return output; } }
来源:https://www.cnblogs.com/Jason-Jan/p/7919311.html