美文网首页
圆形ImageView的几种实现

圆形ImageView的几种实现

作者: code希必地 | 来源:发表于2021-09-28 16:14 被阅读0次

1、Paint.setsetXfermode(PorterDuffXfermode xfermode)

PorterDuffXfermode的构造函数如下:

public PorterDuffXfermode(PorterDuff.Mode mode)

PorterDuff.Mode表示混合模式,枚举值有18个,这里使用Mode.SRC_IN来实现圆形。代码很简单:

private void init(Context context) {
    mPaint = new Paint();
    mPaint.setAntiAlias(true);
    mPaint.setColor(0xffffffff);
    porterDuffXfermode = new PorterDuffXfermode(PorterDuff.Mode.SRC_IN);
}


@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);
    this.width = w;
    this.height = h;
}

@Override
protected void onDraw(Canvas canvas) {
    Drawable drawable = getDrawable();
    if (drawable == null) {
        super.onDraw(canvas);
        return;
    }
    Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();
    int layerId = canvas.saveLayer(0, 0, width, height, null, Canvas.ALL_SAVE_FLAG);
        //画目标图像
    canvas.drawCircle(width / 2, height / 2, width / 2, mPaint);
        //设置混合模式
    mPaint.setXfermode(porterDuffXfermode);
        //画源图像
    canvas.drawBitmap(bitmap, 0, 0, mPaint);
    canvas.restoreToCount(layerId);
}

混合模式设置成SRC_IN时,会根据目标图像的透明度来决定源图像的显示与否。在这里目标图像是一个圆心在控件中心,直径为控件的宽(由于是圆形,控件需设置成宽高一致)的圆形,所以在圆形之外的目标图像的透明度为0,则最终显示为圆形图片。
需要注意的是:在使用setXfermode需要调用saveLayer,saveLayer()会生成一个全新的透明的Bitmap,这个Bitmap大小就是我们指定保存的区域大小,在调用saveLayer后所有操作都在这个bitmap上进行的。

在画源图像时,会把之前画布上所有内容都作为目标图像,而在saveLayer新生成的bitmap上,只有圆形,所以除了与圆形相交之外的位置都是空像素。

如果没有调用saveLayer,那么在画源图像时,目标图像是原始画布上所有图像,此时与圆形相交之外的位置不再是空像素了。这样也无法实现圆形的效果了。

如果调用canvas.save()是不是也可以呢?并不行:save()并不会生成一个新的透明像素的bitmap,它只是保存了画布的状态。

2、Paint.setShader(BitmapShader shader)

BitmapShader,它的构造函数如下:

public BitmapShader(Bitmap bitmap, TileMode tileX, TileMode tileY)

这个就相当于PhotoShop中的图案印章工具,bitmap用来指定图案,tileX用来指定当X轴超出单个图片大小时时所使用的重复策略,同样tileY用于指定当Y轴超出单个图片大小时时所使用的重复策略
其中TileMode的取值有:

  • TileMode.CLAMP:用边缘色彩填充多余空间
  • TileMode.REPEAT:重复原图像来填充多余空间
  • TileMode.MIRROR:重复使用镜像模式的图像来填充多余空间
    简单了解了BitmapShader之后,直接上代码
@Override
protected void onDraw(Canvas canvas) {
    Drawable drawable = getDrawable();
    if (drawable == null) {
        super.onDraw(canvas);
        return;
    }
    Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();
    mPaint.setShader(new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP));
    canvas.drawCircle(width / 2, height / 2, width / 2, mPaint);
    mPaint.setShader(null);
}

代码很简单就这几行,不过使用Shader需要注意的就是:无论使用绘图函数绘制多大一块,在哪绘制,都和Shader无关。因为Shader总是在控件的左上角开始,而你绘制的部分只是显示出来的部分而已。没有显示出来的部分,虽然已经生成但是没有显示而已。

3 View.setOutlineProvider(ViewOutlineProvider provider)

在5.0以后Android提供了ViewOutlineProvider,可以动态的为View设置轮廓,具体使用如下:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            circleImageView.setOutlineProvider(new ViewOutlineProvider() {
                @Override
                public void getOutline(View view, Outline outline) {
                    outline.setOval(0,0,view.getWidth(),view.getHeight());
                }
            });
            circleImageView.setClipToOutline(true);
        }

相关文章

网友评论

      本文标题:圆形ImageView的几种实现

      本文链接:https://www.haomeiwen.com/subject/hmqrnltx.html