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,用来干啥呢?

  首先了解一下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开发之自定义圆形的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的使用

  效果如下:

  

  用法如下:

  

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绘制图形的方法
@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;
} }

Android 自定义圆形图片 CircleImageView的更多相关文章

  1. Android自定义圆形图片工具类(CTRL+C加CTRL+V直接使用)

    先贴一下工具类的代码!可直接复制粘贴 public class RoundImageView extends ImageView { private Paint mPaint; //画笔 privat ...

  2. android自定义圆形图片和遇到的问题

    画圆遇到的问题:图片单位不一样,导致图片只能显示出圆的一部分:看代码: public class MyCircleIamge extends ImageView { private Context c ...

  3. 带你体验Android自定义圆形刻度罗盘 仪表盘 实现指针动态改变

    带你体验Android自定义圆形刻度罗盘 仪表盘 实现指针动态改变 转 https://blog.csdn.net/qq_30993595/article/details/78915115   近期有 ...

  4. 自定义圆形头像CircleImageView的使用和源码分析

    http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0806/3268.html tools:context="com.ex ...

  5. Android实现圆形图片

     情景再现: 写Android程序也有一段时间了,今天突然被问怎么实现一个圆形图片,很多app图像是圆形的.但是用户上传的图像可不是圆的,所以问题就来了,需要我们代码实现圆形图片.但是大脑飞转想到第三 ...

  6. Android 绘制圆形图片

    经常在项目中,会遇到使用圆形头像. 然而图片往往不是圆形的,我们须要对图片进行处理.以达到圆形图片的效果.这里.我总结了一下经常使用的android圆形图片的绘制的方法. 主要有以下几种方式:1.画布 ...

  7. android绘制圆形图片的两种方式

    看下效果先 下面有完整的示例代码 使用BitmapShader(着色器) 我们在绘制view 的时候 就是小学上美术课 用水彩笔在本子上画画 使用着色器绘制圆形图片最简单的理解方式 就是把bitmap ...

  8. 自定义圆形图片控件CircleImageView的实现

    package com.loaderman.circleimageviewdemo; import android.content.Context; import android.content.re ...

  9. 【Android开源项目分析】自定义圆形头像CircleImageView的使用和源码分析

    原文地址: http://blog.csdn.net/zhoubin1992/article/details/47258639 效果

随机推荐

  1. 秒懂JSON.parse()与JSON.stringify()的区别

    在网站开发中,Json是最为常见的一种数据交互手段.在使用过程中,常会遇到Json字段串和对象之间进行转换.很多朋友对于JSON.parse() 和JSON.stringify() 的区别,下面为大家 ...

  2. Android Studio使用OpenCV的配置方法

    1.下载 进入官网(http://opencv.org/)下载OpenCV4Android并解压.目录结构如下图所示. 其中,sdk目录即是我们开发opencv所需要的类库:samples目录中存放着 ...

  3. 如何在js中获取到服务器端控件并给其赋值

    如下所示:lbID为服务器端控件ID document.getElementById('<%=lbID.ClientID%>').value = "赋值";

  4. StringBuffer和StringBuilder区别?

    1. String是不可变类,改变String变量中的值,相当于开辟了新的空间存放新的string变量 2. StringBuffer 可变的类,可以通过append方法改变变量的值,且StringB ...

  5. 332. Reconstruct Itinerary (leetcode)

    1. build the graph and then dfs -- graph <String, List<String>>,  (the value is sorted a ...

  6. QT创建与调用Dll方法(包括类成员)--显式调用

    看网上的好多关于QT调用Dll的方法,大部分都是调用函数的,并没有调用C++类成员的情况,即使是有,比如说: 使用Qt编写模块化插件式应用程序 Qt 一步一步实现dll调用(附源码)---(这一篇里没 ...

  7. [NVIDIA编程教程]OpenACC: Directives for GPUs

    NVIDIA已经在过去五年里大力发展CUDA技术,我们估计CUDA开发人员超过15万,很多重要的科学应用正在CUDA的帮助下完成.但是我们仍然有一个很长的路要走,以帮助每个人从GPU计算中享受到好处. ...

  8. Knockout 事件传递参数的方法

    在Knockout中直接使用函数传递参数是不行的,会导致函数在初始化时就被调用. 要实现参数的传递,有2种方法: 1.方法一:使用函数包裹 <div data-bind="event: ...

  9. Vue nodejs商城项目-搭建express框架环境

    1.express-project 搭建express框架环境 安装express generator生成器 通过生成器自动创建项目 配置分析 安装 cnpm i -g express-generat ...

  10. CentOS 7 下 jdk8 安装教程

    方法一: 一.下载   官网下载地址   下载需要确认当前系统是32位还是64位,可通过命令查询:   sudo uname --m   根据查询结果下载对应的jdk版本(如):   i686 //表 ...