美文网首页
圆形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