Android 自定义圆形头像
先上效果图,如下:
这是有边框的圆形ImageView的效果图,如果想没有边框或者改变边框的颜色都可以通过代码进行设置,下面直接上代码:
package com.example.admin.viewtest;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.NinePatchDrawable;
import android.support.v4.content.ContextCompat;
import android.util.AttributeSet;
import android.view.View;
/**
* 此类实现了圆形ImageView的功能
*/
public class CircleImageView extends View {
private Bitmap mBitmap;
private int mLineColor;
private int mLineWidth;
private Paint mPaint = new Paint();
private Context mContext;
public CircleImageView(Context context) {
super(context);
init(context, null);
}
public CircleImageView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
public CircleImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
private void init(Context context, AttributeSet attrs) {
this.mContext = context;
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.CircleImageView);
BitmapDrawable drawable = (BitmapDrawable) ta.getDrawable(R.styleable.CircleImageView_src);
if (drawable != null)
mBitmap = drawable.getBitmap();
mLineColor = ta.getColor(R.styleable.CircleImageView_line_color, Color.WHITE);
mLineWidth = (int) ta.getDimension(R.styleable.CircleImageView_line_width, 0);
squareBitmap();
ta.recycle();
mPaint.setAntiAlias(true);
mPaint.setColor(mLineColor);
mPaint.setStrokeWidth(mLineWidth);
}
/**
* 将图片处理为正方形图片
*/
private void squareBitmap() {
if (mBitmap != null && mBitmap.getWidth() != mBitmap.getHeight()) {
int wh = Math.min(mBitmap.getWidth(), mBitmap.getHeight());
int num = Math.abs((mBitmap.getWidth() - mBitmap.getHeight()) / 2);
if (mBitmap.getHeight() >= mBitmap.getWidth()) {
mBitmap = Bitmap.createBitmap(mBitmap, 0, num, wh, wh);
} else {
mBitmap = Bitmap.createBitmap(mBitmap, num, 0, wh, wh);
}
}
}
@Override
public void draw(Canvas canvas) {
if (mBitmap != null) {
int w = getWidth() - getPaddingLeft() - getPaddingRight();
int h = getHeight() - getPaddingTop() - getPaddingBottom();
int bw = mBitmap.getWidth();
/**
* 根据画布大小缩放图片
*/
Matrix matrix = new Matrix();
if (w >= h) {
matrix.setScale(h / (float) bw, h / (float) bw);
} else {
matrix.setScale(w / (float) bw, w / (float) bw);
}
mBitmap = Bitmap.createBitmap(mBitmap, 0, 0, bw, bw, matrix, true);
int width = 0;
int left;
int top;
/**
* 确定图片的位置,这里考虑了设置的padding,如果不处理padding的值,那么设置的padding将失效
*/
if (mBitmap != null)
width = mBitmap.getWidth();
if (w >= h) {
left = getPaddingLeft() + Math.abs((w - h) / 2);
top = getPaddingTop();
} else {
left = getPaddingLeft();
top = getPaddingTop() + Math.abs((w - h) / 2);
}
canvas.drawBitmap(createCircleImage(mBitmap, width), left, top, mPaint);
mPaint.setColor(mLineColor);
mPaint.setStrokeWidth(mLineWidth);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setAntiAlias(true);
canvas.drawCircle((width / 2) + left, width / 2 + top, width / 2 - mLineWidth, mPaint);
}
}
/**
* 绘制圆形图片
*
* @param source
* @param min
* @return
*/
private Bitmap createCircleImage(Bitmap source, int min) {
Paint p = new Paint();
p.setAntiAlias(true);
Bitmap target = Bitmap.createBitmap(min, min, Bitmap.Config.ARGB_8888);
/**
* 产生一个同样大小的画布
*/
Canvas canvas = new Canvas(target);
/**
* 首先绘制圆形
*/
canvas.drawCircle(min / 2, min / 2, min / 2 - mLineWidth, p);
/**
* 使用SRC_IN,参考上面的说明
*/
p.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
/**
* 绘制图片
*/
canvas.drawBitmap(source, 0, 0, p);
return target;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int widthMeasureMode = MeasureSpec.getMode(widthMeasureSpec);
int widthMeasureSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMeasureMode = MeasureSpec.getMode(heightMeasureSpec);
int heightMeasureSize = MeasureSpec.getSize(heightMeasureSpec);
int pd = getPaddingBottom();
int pt = getPaddingTop();
int pl = getPaddingLeft();
int pr = getPaddingRight();
int width = 0;
int height = 0;
/**
* 获取设置的图片的宽高
*/
if (mBitmap != null) {
width = mBitmap.getWidth();
height = mBitmap.getHeight();
}
/**
*当宽、高设置为wrap_content时,Mode为MeasureSpec.AT_MOST最大模式;
*当宽、高设置为match_parent或者具体的值时,Mode为MeasureSpec.EXACTLY精确模式;
*在测量View的宽、高时,需要对padding做处理,不然设置的padding将会失效
*/
if (widthMeasureMode == MeasureSpec.AT_MOST && heightMeasureMode == MeasureSpec.AT_MOST) {
setMeasuredDimension(width + pl + pr, height + pd + pt);
} else if (widthMeasureMode == MeasureSpec.AT_MOST && heightMeasureMode == MeasureSpec.EXACTLY) {
setMeasuredDimension(width + pl + pr, heightMeasureSize);
} else if (widthMeasureMode == MeasureSpec.EXACTLY && heightMeasureMode == MeasureSpec.EXACTLY) {
setMeasuredDimension(widthMeasureSize, heightMeasureSize);
} else if (widthMeasureMode == MeasureSpec.EXACTLY && heightMeasureMode == MeasureSpec.AT_MOST) {
setMeasuredDimension(widthMeasureSize, height + pd + pt);
}
}
public void setImageBitmap(Bitmap bitmap) {
recycleBitmap();
this.mBitmap = bitmap;
squareBitmap();
invalidate();
}
public void setImageDrawable(Drawable drawable) {
setImageBitmap(drawable == null ? null : drawableToBitmap(drawable));
}
public void setImageResource(int resId) {
setImageDrawable(ContextCompat.getDrawable(mContext, resId));
}
public void setLineColorResource(int resId) {
setLineColor(ContextCompat.getColor(mContext, resId));
}
public void setLineColor(int color) {
mLineColor = color;
invalidate();
}
/**
* 设置线的宽度
*
* @param width 这个宽度的单位是px
*/
public void setLineWidth(int width) {
mLineWidth = width;
invalidate();
}
private Bitmap drawableToBitmap(Drawable drawable) {
if (drawable instanceof BitmapDrawable) {
return ((BitmapDrawable) drawable).getBitmap();
} else if (drawable instanceof NinePatchDrawable) {
// 取 drawable 的长宽
int w = drawable.getIntrinsicWidth();
int h = drawable.getIntrinsicHeight();
// 取 drawable 的颜色格式
Bitmap.Config config = drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888
: Bitmap.Config.RGB_565;
// 建立对应 bitmap
Bitmap bitmap = Bitmap.createBitmap(w, h, config);
// 建立对应 bitmap 的画布
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, w, h);
// 把 drawable 内容画到画布中
drawable.draw(canvas);
return bitmap;
} else {
return null;
}
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
recycleBitmap();
}
/**
* 释放图片资源
*/
private void recycleBitmap() {
if (mBitmap != null) {
mBitmap.recycle();
mBitmap = null;
}
}
}
上面就是自定义View的全部代码了,代码的关键位置都写了注释,同时也很简单,相信大家一看就懂了,所以不多做解释。本自定义圆形ImageView为了方便在布局中设置图片、边框颜色和边框宽度,在attrs.xml
文件中添加了以下属性:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="CircleImageView">
<attr name="src" format="reference"></attr>
<attr name="line_color" format="color"></attr>
<attr name="line_width" format="dimension"></attr>
</declare-styleable>
</resources>
同时在初始化控件的时候获取了设置的属性:
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.CircleImageView);
BitmapDrawable drawable = (BitmapDrawable) ta.getDrawable(R.styleable.CircleImageView_src);
if (drawable != null)
mBitmap = drawable.getBitmap();
mLineColor = ta.getColor(R.styleable.CircleImageView_line_color, Color.WHITE);
mLineWidth = (int) ta.getDimension(R.styleable.CircleImageView_line_width, 0);
ta.recycle();
这里需要注意在使用完TypedArray 之后,需要及时的调用ta.recycle()释放资源。
以上就是自定义圆形ImageView的所有代码和说明了,大家有不懂的欢迎留言。