效果截图
实现原理
对于圆形头像的实现,其实就是对方形图像做某些处理,以达到圆形头像的效果。一般我们会通过Canvas和Paint结合来实现这种效果。
自定义View来实现
因为圆形头像是视觉方面的需求,一般我们会考虑能否从自定义View的角度来解决问题。自定义的核心有两点:视觉和交互。视觉由onMeasure
、onLayout
、onDraw
这三个方法来完成,而交互则是由dispatchTouchEvent
、onInterceptTouchEvent
、onTouchEvent
等这几个方法来控制,只要处理好这几个方法,就能实现形态各异的自定义View了。
方式一 BitmapShader
package com.yds.myapplication;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import androidx.appcompat.widget.AppCompatImageView;
/**
* Created by yds
* on 2020/3/10.
*/
public class CircleImageView extends AppCompatImageView {
private int mSize;
private Paint mPaint;
public CircleImageView(Context context) {
this(context,null);
}
public CircleImageView(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public CircleImageView(Context context,AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init(){
mPaint = new Paint();
mPaint.setDither(true);
mPaint.setAntiAlias(true);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = getMeasuredWidth();
int height = getMeasuredHeight();
mSize = Math.min(width,height); //取宽高的最小值
setMeasuredDimension(mSize,mSize); //设置CircleImageView为等宽高
}
@Override
protected void onDraw(Canvas canvas) {
//获取sourceBitmap,即通过xml或者java设置进来的图片
Drawable drawable = getDrawable();
if (drawable == null) return;
Bitmap sourceBitmap = ((BitmapDrawable)getDrawable()).getBitmap();
if (sourceBitmap != null){
//对图片进行缩放,以适应控件的大小
Bitmap bitmap = resizeBitmap(sourceBitmap,getWidth(),getHeight());
drawCircleBitmapByShader(canvas,bitmap); //利用BitmapShader实现
}
}
private Bitmap resizeBitmap(Bitmap sourceBitmap,int dstWidth,int dstHeight){
int width = sourceBitmap.getWidth();
int height = sourceBitmap.getHeight();
float widthScale = ((float)dstWidth) / width;
float heightScale = ((float)dstHeight) / height;
//取最大缩放比
float scale = Math.max(widthScale,heightScale);
Matrix matrix = new Matrix();
matrix.postScale(scale,scale);
return Bitmap.createBitmap(sourceBitmap,0,0,width,height,matrix,true);
}
private void drawCircleBitmapByShader(Canvas canvas,Bitmap bitmap){
BitmapShader shader = new BitmapShader(bitmap,BitmapShader.TileMode.CLAMP,BitmapShader.TileMode.CLAMP);
mPaint.setShader(shader);
canvas.drawCircle(mSize / 2,mSize /2 ,mSize / 2,mPaint);
}
}
方式二 PorterDuffXfermode
package com.yds.myapplication;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.util.AttributeSet;
import androidx.appcompat.widget.AppCompatImageView;
/**
* Created by yds
* on 2020/3/10.
*/
public class CircleImageViewPD extends AppCompatImageView {
private int mWidth;
private int mHeight;
private Paint mPaint;
private Bitmap CircleBitmap;
public CircleImageViewPD(Context context) {
super(context);
}
public CircleImageViewPD(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CircleImageViewPD(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
private void ImgCircle(){
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setAntiAlias(true);
paint.setFilterBitmap(true);
paint.setColor(Color.GRAY);
paint.setStrokeWidth(5);
paint.setStyle(Paint.Style.FILL);
CircleBitmap = Bitmap.createBitmap(mWidth,mHeight, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(CircleBitmap);
canvas.drawCircle(mWidth/2,mHeight/2,mWidth/2,paint);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
mWidth = getMeasuredWidth();
mHeight = getMeasuredHeight();
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setFilterBitmap(true);
ImgCircle();
}
@Override
protected void onDraw(Canvas canvas) {
int count = canvas.saveLayerAlpha(0, 0, mWidth, mHeight, 250, Canvas.ALL_SAVE_FLAG);
super.onDraw(canvas);
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
canvas.drawBitmap(CircleBitmap,0,0, mPaint);
canvas.restoreToCount(count);
}
}
方式三 继承自Drawable
package com.yds.myapplication;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.Shader;
import android.graphics.drawable.Drawable;
/**
* Created by yds
* on 2020/3/10.
*/
public class CircleImageViewDrawable extends Drawable {
private Paint mPaint;
private BitmapShader mBitmapShader;
private int mSize;
private int mRadius;
public CircleImageViewDrawable(Bitmap bitmap){
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mBitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP,Shader.TileMode.CLAMP);
mPaint.setShader(mBitmapShader);
mSize = Math.min(bitmap.getWidth(),bitmap.getHeight());
mRadius = mSize/2;
}
@Override
public void draw(Canvas canvas) {
canvas.drawCircle(mRadius,mRadius,mRadius,mPaint);
}
@Override
public void setAlpha(int alpha) {
mPaint.setAlpha(alpha);
}
@Override
public void setColorFilter(ColorFilter colorFilter) {
mPaint.setColorFilter(colorFilter);
}
@Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
}
@Override
public int getIntrinsicHeight() {
return mSize;
}
@Override
public int getIntrinsicWidth() {
return mSize;
}
}
使用
public class MainActivity extends AppCompatActivity {
private ImageView mImageView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mImageView = findViewById(R.id.img);
Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.img);
Drawable drawable = new CircleImageViewDrawable(bitmap);
mImageView.setImageDrawable(drawable);
}
}
地址:https://github.com/ydslib/CircleImageView.git