圆形ImageView系列(二)-----Xfermode+ImageView

前言

上一篇文章《 圆形ImageView系列(一)—–Xfermode+View》介绍了Xfermode,并且结合View实现了圆形ImageView,这种方式实现的思路和方法都很简单,但是使用起来总感觉少了点什么。

既然是圆形ImageView,但是原生的ImageView的很多属性却使用不了,比如scaleType等等,所以下面我们使用第二种方案。

主要原理

在ImageView的上面覆盖一个遮罩层,将这个遮罩层的中间抠掉一个圆形之后,整个ImageView看起来就能显示出圆形的效果了。

先来看看效果图。


圆形ImageView系列(二)-----Xfermode+ImageView_第1张图片

上面那张效果图里,下面的两张图可以明显的看到有个白色的遮罩层覆盖在ImageView上面,所以看起来就显示成了圆形ImageView的效果。

具体实现

package com.passerby.androidadvanced.circleimage.imageview;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.widget.ImageView;

/** * Created by mac on 16/2/3. */
public class CircleLayerImageView extends ImageView {

    public CircleLayerImageView(Context context) {
        this(context, null);
    }

    public CircleLayerImageView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public CircleLayerImageView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        int width = getMeasuredWidth();
        int height = getMeasuredHeight();

        //创建跟imageview相同宽高的遮罩层
        int min = Math.min(width, height);
        Bitmap bitmapMask = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        Canvas canvasMask = new Canvas(bitmapMask);

        //遮罩层颜色
        int maskColor;
        Drawable background = getBackground();
        if (background != null && background instanceof ColorDrawable) {

            maskColor = ((ColorDrawable) background).getColor();
        } else {

            maskColor = Color.WHITE;
        }
        canvasMask.drawColor(maskColor);

        Paint paint = new Paint();
        paint.setAntiAlias(true);
        paint.setColor(Color.WHITE);

        canvas.saveLayer(0, 0, width, height, paint, Canvas.ALL_SAVE_FLAG);

        canvas.drawBitmap(bitmapMask, 0, 0, paint);

        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT));

        canvas.drawCircle(width >> 1, height >> 1, min >> 1, paint);

        canvas.restore();
    }
}

看到这么少的代码是不是吓尿了,之所以这么少是因为是直接继承的ImageView,很多工作ImageView已经帮我们完成了。

代码第34行,要记得调用父类的onDraw方法,不然imageView原本的图片没法正常显示。

第39~42行,创建了一个跟imageView相同大小的遮罩层Bitmap,新建了一个canvas并且将bitmap作为参数传进去。注意这里是新建的一个canvas,而不是直接使用onDraw里面系统传入的canvas,因为我们只需要对这个遮罩bitmap画上颜色而已,如果直接使用系统的canvas,那遮罩层的颜色就画在imageView上面而不是遮罩bitmap上面了。

第44~54行,主要设置遮罩层的颜色,这个颜色从ImageView的background属性中获取,这样就不会使遮罩层显得十分突兀,比如你可以看看上面效果图里面我做了一个actionBar的效果,将圆形ImageView的background跟外面的布局颜色设置成一样,看上去效果就非常好了。

当然为了容错,有人可能不小心将background设置成了图片或者其他drawable,这里默认就设置成白色的遮罩层颜色。

第60~68行,一共5行代码,主要用到了canvas的layer知识。了解photoshop的同学对图层的概念应该非常熟悉,包括我们常用的地图软件也有很多不同的图层,具体知识请百度,这里只需要注意canvas.saveLayer和canvas.restore要成对使用就好。

第62行,将遮罩层画在新的图层上,遮罩层将作为src。

第64行,改变画笔的xfermode模式,对照之前的表,应该选取srcOut模式。

第66行,将适当大小的圆画在遮罩层上面,结合画笔的xfermode模式,画完之后的效果相当于遮罩层被抠掉了一个圆形,位于遮罩层之下的imageview就显示成圆形的效果了。

你可能感兴趣的:(圆形ImageView系列(二)-----Xfermode+ImageView)