android 自定义圆角view,Android 自定义View - 实现圆角图片的几种方式

圆角图片在日常开发是非常常见,所以掌握它也是必要。之前也掌握相关有效的方法,但是从来没有总结过,今天写一篇文章来专门总结已知的方法。本文会介绍三种实现圆角图片的方法,同时也会介绍他们直接的区别。

1. clipPath方法

第一种方法通过Canvas的clipPath来实现,我们先来看一下相关实现代码:

public class RoundImageViewByClipPath extends ImageView {

private Path mPath;

private PaintFlagsDrawFilter mPaintFlagsDrawFilter;

private RectF mRectF;

private float[] mRadius = new float[]{100, 100, 100, 100, 100, 100, 100, 100};

public RoundImageViewByClipPath(Context context) {

this(context, null);

}

public RoundImageViewByClipPath(Context context, @Nullable AttributeSet attrs) {

this(context, attrs, 0);

}

public RoundImageViewByClipPath(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {

super(context, attrs, defStyleAttr);

init();

}

@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)

public RoundImageViewByClipPath(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {

super(context, attrs, defStyleAttr, defStyleRes);

init();

}

private void init() {

mPath = new Path();

mPaintFlagsDrawFilter = new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);

}

@Override

protected void onDraw(Canvas canvas) {

if (mRectF == null) {

mRectF = new RectF();

mRectF.set(0, 0, getMeasuredWidth(), getMeasuredHeight());

}

mPath.addRoundRect(mRectF, mRadius, Path.Direction.CW);

canvas.setDrawFilter(mPaintFlagsDrawFilter);

canvas.clipPath(mPath);

super.onDraw(canvas);

}

}

clipPath方法会将绘制的图形裁剪下来,我们向Path中添加了一个带圆角的矩形,所以后面绘制的图片自然而然就变成了圆角图片。

这种方法的优缺点也是非常明显的:

优点:简单。

缺点:绘制出来的圆角图片带锯齿。这一点是非常不能忍,所以我们通常不会用此方式来实现圆角图片。

2. Xfermode方法

接下来,我们来看一下第二种方式--通过Xfermode来实现圆角图片。我们先来看看代码实现:

public class RoundedImageViewByXfermode extends ImageView {

private Paint mPaint;

private Xfermode mXfermode = new PorterDuffXfermode(PorterDuff.Mode.SRC_IN);

private RectF mRectF;

private Bitmap mBitmap;

public RoundedImageViewByXfermode(Context context) {

this(context, null);

}

public RoundedImageViewByXfermode(Context context, @Nullable AttributeSet attrs) {

this(context, attrs, 0);

}

public RoundedImageViewByXfermode(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {

super(context, attrs, defStyleAttr);

init();

}

@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)

public RoundedImageViewByXfermode(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {

super(context, attrs, defStyleAttr, defStyleRes);

}

private void init() {

mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);

}

@Override

protected void onDraw(Canvas canvas) {

canvas.saveLayer(0, 0, getMeasuredWidth(), getMeasuredHeight(), null, Canvas.ALL_SAVE_FLAG);

Drawable drawable = getDrawable();

if (mBitmap == null) {

mBitmap = Bitmap.createBitmap(getMeasuredWidth(), getMeasuredHeight(), Bitmap.Config.ARGB_8888);

Canvas drawCanvas = new Canvas(mBitmap);

drawable.draw(drawCanvas);

}

if (mRectF == null) {

mRectF = new RectF(0, 0, getMeasuredWidth(), getMeasuredHeight());

}

mPaint.setXfermode(null);

canvas.drawRoundRect(mRectF, 100, 100, mPaint);

mPaint.setXfermode(mXfermode);

canvas.drawBitmap(mBitmap, 0, 0, mPaint);

canvas.restore();

}

}

其实呢,使用Xfermode实现圆角图片的原理非常简单,先绘制Dst图层和src图层,然后根据谷歌爸爸给定的规则设置不同的Xfermode,从而达到裁剪图层的效果。也就是下面这张图片:

5d4909e72153

使用Xfermode通常来说会绘制两层,第一层称为Dst图层,第二层称为src图层,然后根据Xfermode来去计算两个图层的关系。

canvas有一个默认的layer,平时我们调用的drawXXX方法所绘制的内容都是这个layer上面。而使用Xfermode需要注意的地方是,我们直接将内容绘制在这个默认的layer上面,而是必须绘制在一个新的layer上面,然后通过restore或者restoreToCount将新layer的内容绘制在默认的layer上面,如此操作才是正确的;除此之外,也可以通过新的bitmap来实现。具体的介绍,可以参考:Android PorterDuffXfermode使用中的一些坑。

而这种方法的优缺点呢?

优点:可定义高,支持多图层的圆角。

缺点:麻烦。

3. BitmapShader

最后一种方法就是通过BitmapShader方法来实现,这种方法也是极力推荐,如果你的要求仅仅是图片实现圆角,推荐这种方法,为什么呢?我们先来看看相关实现:

public class RoundImageViewByBitmapShader extends ImageView {

private Shader mShader;

private Paint mPaint;

public RoundImageViewByBitmapShader(Context context) {

super(context);

}

public RoundImageViewByBitmapShader(Context context, @Nullable AttributeSet attrs) {

super(context, attrs);

}

public RoundImageViewByBitmapShader(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {

super(context, attrs, defStyleAttr);

}

@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)

public RoundImageViewByBitmapShader(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {

super(context, attrs, defStyleAttr, defStyleRes);

}

@Override

protected void onDraw(Canvas canvas) {

BitmapDrawable drawable = (BitmapDrawable) getDrawable();

if (mShader == null) {

mShader = new BitmapShader(drawable.getBitmap(), Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);

mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);

}

mPaint.setShader(mShader);

canvas.drawRoundRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), 100, 100, mPaint);

}

}

具体就是上面的,至于为什么这样就能实现圆角,大家可以参考这篇文章:Android之Shader完全理解指南。

优点:简单并且有效。

确定:仅支持Bitmap圆角,如果是LayerDrawable就显得手足无措。

5. 总结

就目前而言,常见的实现圆角的方式就是上面三种,通常来说,我们选择第2种或者第3种方法,而第一种方法不推荐使用。

而如果你的圆角要求仅限于纯图片,推荐第3种方式,因为比较简单;如果需要支持复杂的情形,比如LayerDrawable,推荐使用第2种方式。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值