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

来源:互联网 发布:protobuffer java 编辑:程序博客网 时间:2024/05/29 10:49

前言

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

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

主要原理

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

先来看看效果图。


我爱提莫~

上面那张效果图里,下面的两张图可以明显的看到有个白色的遮罩层覆盖在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就显示成圆形的效果了。

0 0