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;
}
} @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;
} }
Android 自定义圆形图片 CircleImageView的更多相关文章
- Android自定义圆形图片工具类(CTRL+C加CTRL+V直接使用)
先贴一下工具类的代码!可直接复制粘贴 public class RoundImageView extends ImageView { private Paint mPaint; //画笔 privat ...
- android自定义圆形图片和遇到的问题
画圆遇到的问题:图片单位不一样,导致图片只能显示出圆的一部分:看代码: public class MyCircleIamge extends ImageView { private Context c ...
- 带你体验Android自定义圆形刻度罗盘 仪表盘 实现指针动态改变
带你体验Android自定义圆形刻度罗盘 仪表盘 实现指针动态改变 转 https://blog.csdn.net/qq_30993595/article/details/78915115 近期有 ...
- 自定义圆形头像CircleImageView的使用和源码分析
http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0806/3268.html tools:context="com.ex ...
- Android实现圆形图片
情景再现: 写Android程序也有一段时间了,今天突然被问怎么实现一个圆形图片,很多app图像是圆形的.但是用户上传的图像可不是圆的,所以问题就来了,需要我们代码实现圆形图片.但是大脑飞转想到第三 ...
- Android 绘制圆形图片
经常在项目中,会遇到使用圆形头像. 然而图片往往不是圆形的,我们须要对图片进行处理.以达到圆形图片的效果.这里.我总结了一下经常使用的android圆形图片的绘制的方法. 主要有以下几种方式:1.画布 ...
- android绘制圆形图片的两种方式
看下效果先 下面有完整的示例代码 使用BitmapShader(着色器) 我们在绘制view 的时候 就是小学上美术课 用水彩笔在本子上画画 使用着色器绘制圆形图片最简单的理解方式 就是把bitmap ...
- 自定义圆形图片控件CircleImageView的实现
package com.loaderman.circleimageviewdemo; import android.content.Context; import android.content.re ...
- 【Android开源项目分析】自定义圆形头像CircleImageView的使用和源码分析
原文地址: http://blog.csdn.net/zhoubin1992/article/details/47258639 效果
随机推荐
- AOSP 源码下载
网上关于这块大部分教程都是无效的,因为墙的缘故,无法使用官方提供的下载链接,我这里使用了清华大学的镜像,是能够顺利将 AOSP 下载下来.如果你还没有安装 Ubuntu,请看<VirtualBo ...
- Android开发由eclipse转Android Studio中一些常见出错问题解决方法
1.给一个Activity添加了一个Dialog主题,结果出现了下面的问题,在eclipse却没有出错 <activity android:name=".DialogActivity& ...
- 责任链模式(ChainOfResponsibiliby、Filter)
Request 类: package com.demo; public class Request { private String requestStr; public String getRequ ...
- DOM对象和js对象以及jQuery对象的区别
DOM对象和js对象以及jQuery对象的区别 DOM对象和js对象以及jQuery对象的区别 一.DOM对象 文档对象模型简称DOM,是W3C组织推荐的处理可扩展置标语言的标准编程接口. DOM实际 ...
- php的yii框架开发总结8
EMailer是一个简单的封装PHPMailer类.利用这个扩展可以实现发邮件的功能. 下载地址:http://www.yiiframework.com/extension/mailer/ 下载解压把 ...
- php一个类引用另一个类的方法的写法
default.php: <?php namespace SiteInfo{ class Site{ var $url; var $title; function setUrl($par){ $ ...
- 最终类object 和内部类
Object 类 性质:[1]是所有类的根类. [2]如果一个类没有显示继承另外一个类,那么该类一定继承于Object toString() 返回对象的字符串表示形式 特殊:[ ...
- halcon保存带有region的图片算子
显示带区域的图片除了可以用dev_display挨个显示外再截图,还可以通过一个算子来实现这一功能 这个算子是:dump_window_image.(其实就是截图) 这个算子的意思是把WindowHa ...
- Python中的__name__和__main__含义详解
1背景 在写Python代码和看Python代码时,我们常常可以看到这样的代码: ? 1 2 3 4 5 def main(): ...... if __name == "__m ...
- ceph-对象存储
ceph对象存储 作为文件系统的磁盘,操作系统不能直接访问对象存储.相反,它只能通过应用程序级别的API访问.ceph是一种分布式对象存储系统,通过ceph对象网关提供对象存储接口,也称为RADOS网 ...