实现原理,通过裁切canvas来控制绘制效果,canvas有drawRoundRect可以直接绘制圆角矩形,但是没有直接裁切圆角矩形的方法。如果想这么做,就需要通过path来裁切canvas了
让自己的类继承自ImageView,声明实例变量
private int round=10,width,height; //width可以在onLayout方法中通过getWidth()方法获取,height同理 private Path path; //记得在构造方法中对path进行初始化,不要将初始化放在draw方法,draw会重复调用,如果在这个方法中创建对象,容易频繁触发内存回收,导致卡顿 @Override protected void onDraw(Canvas canvas) { if (height>round&&width>round){ path.moveTo(round,0); path.lineTo(width-round,0); path.quadTo(width,0,width,round); path.lineTo(width,height-round); path.quadTo(width,height,width-round,height); path.lineTo(round,height); path.quadTo(0,height,0,height-round); path.lineTo(0,round); path.quadTo(0,0,round,0); } canvas.clipPath(path); super.onDraw(canvas);通过path的quadTo方法,可以很轻松的实现圆角,如果没有接触过这个方法,很可能对这个方法的参数不好理解,这边简单解释一下。
quadTo(float x1, float y1, float x2, float y2)方法需要传入四个浮点型,其实为两个点的坐标,第一个点(x1,y1),第二个点(x2,y2),第二个点比较好理解,就是path在调用这个方法后,最后到达(x2,y2)的位置,第一个点为控制点
再解释第一个点的作用前,先看一下很好理解的lineTo方法,代码很简单,就是从(50,50)的位置开始,先到(250,50),再到(250,250)
path.moveTo(50,50); path.lineTo(250,50); path.lineTo(250,250);现在再调用一下quadTo方法,把直角的这个点(250,50)作为控制点
path.moveTo(50,50); path.lineTo(250,50); path.lineTo(250,250); canvas.drawPath(path,paint); path.reset(); path.moveTo(50,50); path.quadTo(250,50,250,250); canvas.drawPath(path,paint);这样对比的话,控制点就比较好理解了,正常情况下,两条线本来需要相交的点,即为控制点
除此之外,还可以通过path的addRoundRect来生成圆角矩阵,这个方法需要传入一个矩阵、x轴与y轴生成椭圆角的半径、绘制方向。
CircleRactImagView.class
import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Path; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import android.graphics.Rect; import android.graphics.RectF; import android.util.AttributeSet; public class CircleRactImagView extends androidx.appcompat.widget.AppCompatImageView { private Paint paint; private int round=15,width,height; private Path path; public CircleRactImagView(Context context) { this(context, null); } public CircleRactImagView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public CircleRactImagView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(); } private void init(){ paint = new Paint(); path=new Path(); } public int getRound() { return round; } public void setRound(int round) { this.round = round; invalidate(); } @Override protected void onDraw(Canvas canvas) { buildPath(); canvas.clipPath(path); super.onDraw(canvas); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); width=getWidth(); height=getHeight(); } private void buildPath(){ if (!(height>=round*2)||!(width>=round*2)){ round=Math.min(height/2,width/2); } path.moveTo(round,0); path.lineTo(width-round,0); path.quadTo(width,0,width,round); path.lineTo(width,height-round); path.quadTo(width,height,width-round,height); path.lineTo(round,height); path.quadTo(0,height,0,height-round); path.lineTo(0,round); path.quadTo(0,0,round,0); } }默认的圆角是15px,不需要更改的话,直接当作ImageView使用就可以,如果需要修改,调用setRound(int round)方法,设置后会自动调用invalidate()重绘,无需手动刷新。