美文网首页
圆形头像的两种实现方法

圆形头像的两种实现方法

作者: 做梦枯岛醒 | 来源:发表于2019-09-29 20:17 被阅读0次

    之前认为圆形头像非常难实现,系统为啥不提供一个属性来支持一下圆角呢?后来在做项目的时候就一直用大神的开源库。
    https://github.com/hdodenhof/CircleImageView,这是一个很方便的库,所以就没有再研究圆形头像。

    后来突然要学习自定义View就一起研究了一下。当然实现圆角头像的方法有很多,我这里只列举其中两种。

    Xfermode

    第一种实现方案是XferMode。
    Google提供了一系列的Mode来实现图层叠加的不同效果,这一功能跟PhotoShop等软件中的布尔运算是差不多的。

    光看图有点抽象,我们看看圆形头像场景下,我们要用到哪种模式。
    首先我粗略的实现了一个效果,简单的看一下代码。

    public class CircleHeadXferMode extends View {
        private Paint mPaint;
        private Bitmap bitmap;
        private int width;
        private int height;
        private Bitmap out;
    
        public CircleHeadXferMode(Context context) {
            super(context);
            init(context);
        }
    
        public CircleHeadXferMode(Context context, AttributeSet attrs) {
            super(context, attrs);
            init(context);
        }
    
        public CircleHeadXferMode(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            init(context);
        }
    
    
        private void init(Context context) {
            mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
            setLayerType(LAYER_TYPE_SOFTWARE, null);
            bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.a);
            width = bitmap.getWidth();
            height = bitmap.getHeight();
        }
    
    
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            canvas.drawCircle(width/2,width/2,width/2,mPaint);
            mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
            canvas.drawBitmap(bitmap,0,0,mPaint);
        }
    }
    

    这里我直接继承自View,实现了一个自定义View,当然初始化方法这里我就不赘述了。

    init方法中也是一些简单的初始化操作,bitmap是在一个本地资源中加载的,获取他的宽高作为后面绘制的尺寸,由于这里我用的是一个方形图片,所以没有对尺寸做特殊处理。

    在onDraw方法中,先绘制了一个圆形,这个就是我们圆形头像的边界,然后我设置XferMode,这里选择的是一个SRC_IN的形式。

    根据上面的Mode图片,可以看到SrcIn是取了两个图层的子集,其中Src和Dst分别是两个图层,关于SrcIn和DstIn的区别我们后面看效果再说。

    最后绘制了图像。看一下效果。


    对于DstIn是这种效果(画笔默认的黑色)。


    所以可以看到,对于SRCIN和DSTIN就是对于图层调整了位置的交集,前者是后写的在上面,后者是前写的在上面。

    对于其他的尺寸缩放的问题这里不再赘述,主要是看看如何实现一个圆形头像。

    Clip

    第二种方法同样很简单,是借助于一个canvas的clip功能间接实现的圆形。

    public class CircleHead extends View {
    
        private Bitmap bitmap;
        private Paint paint;
        private Path mPath;
    
    
        public CircleHead(Context context) {
            super(context);
            init(context);
        }
    
        public CircleHead(Context context, AttributeSet attrs) {
            super(context, attrs);
            init(context);
        }
    
        public CircleHead(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            init(context);
        }
    
    
        private void init(Context context) {
            //禁用硬件加速功能
            setLayerType(LAYER_TYPE_SOFTWARE, null);
            bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.a);
            paint = new Paint();
            mPath = new Path();
            int width = bitmap.getWidth();
            int height = bitmap.getHeight();
            mPath.addCircle(width / 5, height / 5, width / 5, Path.Direction.CCW);
        }
    
    
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            canvas.save();
            //裁剪为圆形路径
            canvas.clipPath(mPath);
            canvas.drawBitmap(bitmap,0,0,paint);
        }
    }
    

    继承自View,在init方法中初始化了一些内容。
    首先,禁用硬件加速。

    setLayerType(LAYER_TYPE_SOFTWARE, null);
    

    硬件加速开启的时候,会对clip产生影响。

    其次获取bitmap,宽高。
    然后直接构建一个圆形路径,方向为CCW(逆时针),
    最后在onDraw()方法中裁剪圆形路径,并将我们的头像资源绘制上去。
    实现的效果图跟上面贴的一样。

    总结

    实现圆形图片的方法有很多,比如还有Glide,但是Glide处理不好,图片会有缩放不一致的情况,自行缩放可以选择Shader,选择一种比较喜欢的即可。

    ok,就到这里啦。

    相关文章

      网友评论

          本文标题:圆形头像的两种实现方法

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