仿钉钉头像

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/binbinqq86/article/details/78329238

转载请注明出处:http://blog.csdn.net/binbinqq86/article/details/78329238

项目中要用到一个聊天头像的控件,跟钉钉的类似的这种,于是乎自己就想撸一个出来,虽然网上也有现成的,但别人的总是需要修修改改,还不如自己从头开始,也方便后续维护,直接看效果图:

这里写图片描述

怎么样,还不错吧,哈哈~自我感觉良好,唯一不同的是钉钉两个人和三个人是左右横排的,我们的是竖排的。下面我们来简单分析一下实现原理:

首先抛开图片不说,先看底色+昵称,底色就很简单了,根据用户的唯一id,来指定一个规则,进行显示不同的颜色,这个看产品具体来定了,整体就采用canvas的drawCircle、drawArc、drawText等方法来绘制了,看看应该是挺容易的,难点就是具体的坐标计算,只要算准位置,这个自定义view就是分分钟了,哈哈~再来分析一下有图片的情况,图片的绘制当然就是drawBitmap了,另外再加上Xfermode这个强大的效果处理(请参考我上一篇文章—— Canvas的drawBitmap以及Paint的PorterDuffXfermode使用心得),也是分分钟实现我们想要的不规则图片绘制。好了,原理分析完了,下面直接上代码,核心部分就是我们的onDraw方法了:

@Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (count == 0) {
            return;
        }
        //必须先设置字体大小
        if (count == 1) {
            if (textSize1 == 0) {
                return;
            }
        } else {
            if (textSizeOther == 0) {
                return;
            }
        }


        if (count == 1) {
            //一个人(两个汉字)
            deal1(canvas);
        } else if (count == 2) {
            //两个人(上下各两个字)
            deal2(canvas);
        } else if (count == 3) {
            //三个人则上面一个(两个汉字),下面两个(一个汉字)
            deal3(canvas);
        } else {
            //4人以上群聊取前四个人的头像拼接(一个汉字)从左到右,从上到下
            deal4(canvas);

        }
    }

可以看到,这里我们分为四种情况来考虑,每种情况分别处理,首先来看deal1:

private void deal1(final Canvas canvas) {
        if (checkBitmap(list.get(0).bitmap)) {
            //新建Canvas层级
            int saveCount = canvas.saveLayer(0f, 0f, width, height, null, Canvas.ALL_SAVE_FLAG);
            //绘制底图——原来canvas上的内容dst
            canvas.drawBitmap(list.get(0).bitmap, 0, 0, mPaint);

            //生成圆形图片蒙版src
            Bitmap mask = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
            Canvas canvasMask = new Canvas(mask);
            RectF rf = new RectF(0f, 0f, width, height);
            canvasMask.drawOval(rf, mPaint);

            //设置交叉模式,绘制蒙版
            mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
            canvas.drawBitmap(mask, 0, 0, mPaint);

            //还原
            mPaint.setXfermode(null);
            //将如上画的层覆盖到原有层级上
            canvas.restoreToCount(saveCount);
        } else {
            mPaint.setColor(getBgColor(list.get(0).id));
            canvas.drawCircle(width / 2f, height / 2f, width / 2f, mPaint);
            //画名字
            textPaint.setTextSize(textSize1);
            String name = list.get(0).presentName;
            name = name.length() > 2 ? name.substring(name.length() - 2, name.length()) : name;
            if (textColor != 0) {
                textPaint.setColor(textColor);
            }
            //baseLine计算参考:http://blog.csdn.net/harvic880925/article/details/50423762
            Paint.FontMetrics fontMetrics = textPaint.getFontMetrics();
            float baseline = height / 2f + (fontMetrics.bottom - fontMetrics.top) / 2f - fontMetrics.bottom;
            float x = (width - textPaint.measureText(name)) / 2f;
            canvas.drawText(name, x, baseline, textPaint);
        }
    }

这里我们分为有没有图片来分别处理,有头像就绘制用户头像,没有则昵称+底色,drawText方法呢,主要就是涉及到一个baseline的计算,这里大家可以参考这位大神的分析:http://blog.csdn.net/harvic880925/article/details/50423762,讲解的是非常清楚。这段代码其他就没有什么难点了,都是canvas的应用绘制和坐标计算。

同理,当两个用户的时候,头像的处理也是类似,只不过中间加了一个空隙,这个在绘制的时候需要计算进去。另外就是我们在绘制图片的时候,为了让图片居中显示,我们就采用上篇讲过的只绘制bitmap的中间区域,而不是从图片左上角开始绘制,这样就会好很多了。另外就是三个,大于等于四个用户的时候,昵称的绘制如果按照标准的居中,看起来并没有在中间,这是因为扇形的视觉缘故,所以这里我增加了一个偏移量:


    /**
     * x方向的偏移量,用于修正位置
     */
    private float xDelta;
    /**
     * y方向的偏移量,用于修正位置
     */
    private float yDelta;

这两个用来修正文本绘制的视觉位置。

另外关于昵称文本大小颜色等也加入了一些自定义变量去控制,最终调用如下:

     mHiHeaderImageView.setTextSize1(20f).setTextSizeOther(15f).setList(list);

至于后面几种情况,这里就不贴出具体代码了,基本上跟第一种是一样的,无非就是多了坐标的处理而已,至此我们的仿钉钉头像这个控件就完成了,怎么样,简单吧!

同样最后给出源码,感兴趣的同学可以自己下载查看,有疑问的可以在下方留言,谢谢大家~

源码下载

猜你喜欢

转载自blog.csdn.net/binbinqq86/article/details/78329238
今日推荐