首先在values下面创建attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="FilletImageView">
<attr name="shape_mode" format="enum">
<enum name="round_rect" value="1"/>
<enum name="circle" value="2"/>
</attr>
<attr name="round_radius" format="dimension"/>
</declare-styleable>
</resources>
创建类FilletImageView继承AppCompatImageView。完整代码:
package com.example.baselibs.widget;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import android.graphics.Xfermode;
import android.os.Build;
import android.util.AttributeSet;
import androidx.appcompat.widget.AppCompatImageView;
import com.example.baselibs.R;
import java.util.Arrays;
/**
*圆角加载图片控件
*/
public class FilletImageView extends AppCompatImageView {
private static final int SHAPE_MODE_ROUND_RECT=1;
private static final int SHAPE_MODE_CIRCLE=2;
private int mShapeMode=0;//显示形状
private int width,height;
private float[] srcRadii=new float[8];
private float mRadius=0;//半径
private Paint mPaint;//画笔
private RectF srcRectF;//图片占的矩形区域
private Path mPath;//用来裁剪图片的path
private Path srcPath;//图片区域大小的path
private Xfermode xfermode;
public FilletImageView(Context context) {
super(context);
init(null);
}
public FilletImageView(Context context, AttributeSet attrs) {
super(context, attrs);
init(attrs);
}
public FilletImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(attrs);
}
private void init(AttributeSet attrs){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB){
setLayerType(LAYER_TYPE_HARDWARE,null);
}
if (attrs!=null){
TypedArray ta=getContext().obtainStyledAttributes(attrs, R.styleable.FilletImageView);
mShapeMode=ta.getInt(R.styleable.FilletImageView_shape_mode,0);
mRadius=ta.getDimension(R.styleable.FilletImageView_round_radius,0);
ta.recycle();
}
srcRectF=new RectF();
mPath=new Path();
mPaint=new Paint();
if (Build.VERSION.SDK_INT<=Build.VERSION_CODES.O_MR1){
xfermode=new PorterDuffXfermode(PorterDuff.Mode.DST_IN);
}else {
xfermode=new PorterDuffXfermode(PorterDuff.Mode.DST_OUT);
srcPath=new Path();
}
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
width=w;
height=h;
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
if (changed){
switch (mShapeMode){
case SHAPE_MODE_ROUND_RECT://圆角矩形
srcRectF.set(0,0,width,height);
break;
case SHAPE_MODE_CIRCLE://圆形
int min=Math.min(getWidth(),getHeight());
mRadius= min/2.0f;
srcRectF.set(width/2.0f-mRadius,height/2.0f-mRadius,
width/2.0f+mRadius,height/2.0f+mRadius);
break;
}
//填充四个角圆角的半径
Arrays.fill(srcRadii,mRadius);
}
}
@Override
protected void onDraw(Canvas canvas) {
// 使用图形混合模式来显示指定区域的图片
canvas.saveLayer(srcRectF,null,Canvas.ALL_SAVE_FLAG);
super.onDraw(canvas);
//每次绘制前,重置画笔
mPaint.reset();
mPath.reset();
switch (mShapeMode){
case SHAPE_MODE_ROUND_RECT:
mPath.addRoundRect(srcRectF,srcRadii,Path.Direction.CCW);
break;
case SHAPE_MODE_CIRCLE:
mPath.addCircle(width/2.0f,height/2.0f,mRadius,Path.Direction.CCW);
break;
}
//这里要注意,前面重置画笔了,要在这里从新设置
mPaint.setAntiAlias(true);
mPaint.setStyle(Paint.Style.FILL);
mPaint.setXfermode(xfermode);
if (Build.VERSION.SDK_INT<=Build.VERSION_CODES.O_MR1){
canvas.drawPath(mPath,mPaint);
}else {
srcPath.addRect(srcRectF,Path.Direction.CCW);
// 计算tempPath和path的差集
srcPath.op(mPath,Path.Op.DIFFERENCE);
canvas.drawPath(srcPath,mPaint);
}
mPaint.setXfermode(null);
//恢复画布状态
canvas.restore();
}
}
在布局中使用:只需要设置mode和radius两个参数。而且必须两个都要设置才有效果
<com.example.baselibs.widget.FilletImageView
android:id="@+id/iv_app_icon"
android:layout_width="100dp"
android:layout_height="100dp"
app:shape_mode="round_rect"
app:round_radius="30dp"
android:src="@mipmap/em_default_avatar"
tools:ignore="MissingConstraints"/>
网友评论