Android绘制圆形图片的方法总结

在需求开发中经常会遇到需要显示圆形图片的情况,比如我们经常见到的用户圆形头像。为了实现这个效果,我们需要重新定义View,通过重写onDraw方法来使得我们的View显示成圆形。要是实现这个功能主要有三种方法。

使用Xfermode 相交模式

  什么是相交模式?正常的情况下,在已有的图像上绘图将会在其上面添加一层新的形状。如果新的Paint是完全不透明的,那么它将完全遮挡住下面的Paint;如果它是部分透明的,那么它将会被染上下面的颜色。而setXfermode就可以来解决这个问题,设置两张图相交之后的显示模式。canvas原有的图片可以理解为背景,就是dst;新画上去的图片可以理解为前景,就是src。下面是全部的16种相交模式的效果图。

这里写图片描述 
  由上图可以看到,如果我们需要画一个圆形的图,可以有几种方法,比如,可以通过先绘制原图,然后使用DstIn的方式绘制一个圆;或者可以先绘制一个圆,然后通过SrcIn的方式绘制原图。我们使用第一种方法的代码如下:

@Override
protected void onDraw(Canvas canvas) {
    Drawable drawable = getDrawable();
    if (drawable != null) {
        //步骤1:先生成一个bitmap,在bitmap上绘制原图
        bitmap = Bitmap.createBitmap(getWidth(),getHeight(), Bitmap.Config.ARGB_8888);
        Canvas bitmapCanvas = new Canvas(bitmap);
        drawable.setBounds(0, 0, getWidth(), getHeight());
        drawable.draw(bitmapCanvas);

        //步骤2:生成圆形图片蒙版
        Bitmap mask = Bitmap.createBitmap(width, height,Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(mask);
        Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setColor(Color.BLACK);
        canvas.drawOval(new RectF(0.0f, 0.0f, width, height), paint);

        //步骤3:使用DST_IN的方式在原图的bitmap上绘制蒙版图
        mPaint.reset();
        mPaint.setFilterBitmap(false);
        mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
        bitmapCanvas.drawBitmap(mask, 0.0f, 0.0f, mPaint);

        //步骤4:将最后生成的这个bitmap绘制到View的canvas上
        if (bitmap != null) {
            mPaint.setXfermode(null);
            canvas.drawBitmap(bitmap, 0.0f, 0.0f, mPaint);
        }
    }
}

通过裁剪画布区域实现

  Canvas类提供了ClipPath, ClipRect, ClipRegion 等方法来裁剪画布,通过他们的不同组合,可以得到任意形状的画布,然后在这个区域上画图,就可以获得对应形状的View了。但是,使用裁剪画布的方式实现圆形头像会有锯齿,边缘不如其他方式平滑。代码如下:

​//为了保证绘制出来的View为圆形,如果图片的长宽不一致,长的部分会被截断
​@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    int mSize = Math.min(getMeasuredWidth(), getMeasuredHeight());
    mRadius = mSize / 2;
    setMeasuredDimension(mSize, mSize);
}

@Override
protected void onDraw(Canvas canvas) {
    mPath.addCircle(mRadius, mRadius, mRadius, Path.Direction.CW);
    canvas.clipPath(mPath);
    super.onDraw(canvas);
}

使用BitmapShader

  Shader就是画笔Paint的渲染器,本质上这种方法其实是画圆,只是渲染时采用了我们设置的图片。 
  BitmapShader是Shader的子类,可以通过Paint.setShader(Shader shader)进行设置,然后用这个Paint绘图时,就会根据你设置的TileMode,对绘制区域进行着色。BitmapShader的构造方法: 
mBitmapShader = new BitmapShader(bitmap, TileMode.CLAMP, TileMode.CLAMP); 
  参数TileMode的取值有三种: 
CLAMP 拉伸:拉伸的是图片最后的那一个像素 
REPEAT 重复:就是横向、纵向不断重复这个bitmap 
MIRROR 镜像:横向、纵向不断翻转重复 
  代码示例如下:

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    mSize = Math.min(getMeasuredWidth(), getMeasuredHeight());
    mRadius = mSize / 2;
    setMeasuredDimension(mSize, mSize);
}

@Override
protected void onDraw(Canvas canvas) {
    //得到原bitmap
    Bitmap src = ((BitmapDrawable) getDrawable()).getBitmap();
    if (src == null) {
        super.onDraw(canvas);
        return;
    }
    //把bitmap缩小为和View大小一致
    Bitmap newBitmp = Bitmap.createScaledBitmap(src, mSize, mSize, false);
    if (newBitmp == null) {
        return;
    }
    //将缩小后的bitmap设置为画笔的shader
    mBitmapShader = new BitmapShader(newBitmp, Shader.TileMode.REPEAT,
            Shader.TileMode.REPEAT);
    //生成用来绘图的bitmap,并在其上用画笔绘图
    Bitmap dest = Bitmap.createBitmap(mSize, mSize, Bitmap.Config.ARGB_8888);
    if (dest == null) {
        return;
    }
    Canvas c = new Canvas(dest);
    Paint paint = new Paint();
    paint.setAntiAlias(true);
    paint.setShader(mBitmapShader);
    c.drawCircle(mRadius, mRadius, mRadius, paint);
    //将最后生成的bitmap绘制到View的canvas上
    canvas.drawBitmap(dest, 0, 0, paint);
}

  上面这三种方法都可以实现圆形头像,也可以实现其他形状,通常第一种实现方式使用的比较多。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值