仿钉钉头像(有头像显示图片拼接,无图显示昵称)

2018-12-14  本文已影响49人  BKQ_SYC

一、需求

  1. 多图拼接展示(目前最多支持四张图)
  2. 可展示文字
  3. 可展示成圆角、方角、圆形
  4. 可自定义分割线宽度、颜色
  5. 可设置是否包含边框

二、预览

预览图.jpg

三、代码

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import android.support.v4.content.ContextCompat;

import java.util.List;

/**
 * Describe : https://github.com/NFLeo
 * Created by Leo on 2018/12/13 on 13:57.
 */
class AvatarUtil {

    static Builder getBuilder(Context context) {
        return new Builder(context);
    }

    public static class Builder {

        private Context mContext;
        private List<Object> mList;                      // 数据源
        private int mWidth = 50;                         // 控件宽度
        private int mHeight = 50;                        // 控件高度

        private int mShape = Shape.CIRCLE;               // 控件形状
        private int mRoundAngel = 10;                    // 圆角大小
        private int mMarginWidth = 4;                    // 图片间隙
        private int mMarginColor = R.color.gray;         // 图片间隙颜色
        private boolean hasEdge = true;                  // 是否包含边缘

        private float mTextSize = 50;                           // 文字大小
        private int mTextColor = R.color.colorPrimary;          // 文字颜色
        private int mBackGroundColor = R.color.colorAccent;     // 文字背景颜色

        private Builder(Context context) {
            this.mContext = context;
        }

        /**
         * 设置数据源
         */
        Builder setList(List<Object> mList) {
            this.mList = mList;
            return this;
        }

        /**
         * 设置图片尺寸
         */
        Builder setBitmapSize(int mWidth, int mHeight) {
            if (mWidth > 0) {
                this.mWidth = mWidth;
            }

            if (mHeight > 0) {
                this.mHeight = mHeight;
            }
            return this;
        }

        /**
         * 设置展示类型(圆形、圆角、方形)
         */
        Builder setShape(int mShape) {
            this.mShape = mShape;
            return this;
        }

        /**
         * 设置圆角角度
         * 当shape设置为Shape.Round时读取改属性
         *
         * @param mRoundAngel 圆角角度
         */
        Builder setRoundAngel(int mRoundAngel) {
            this.mRoundAngel = mRoundAngel;
            return this;
        }

        /**
         * 设置分割线宽度
         */
        Builder setMarginWidth(int mMarginWidth) {
            this.mMarginWidth = mMarginWidth;
            return this;
        }

        /**
         * 设置分割线颜色
         */
        public Builder setMarginColor(int mMarginColor) {
            this.mMarginColor = mMarginColor;
            return this;
        }

        /**
         * 设置文字大小
         */
        public Builder setTextSize(int mTextSize) {
            this.mTextSize = mTextSize;
            return this;
        }

        /**
         * 设置文字颜色
         */
        public Builder setTextColor(int mTextColor) {
            this.mTextColor = mTextColor;
            return this;
        }

        public Builder setHasEdge(boolean hasEdge) {
            this.hasEdge = hasEdge;
            return this;
        }

        Bitmap create() {

            final Bitmap result = Bitmap.createBitmap(mWidth, mHeight, Bitmap.Config.ARGB_8888);
            Canvas canvas = new Canvas(result);

            Paint paint = new Paint();
            paint.setAntiAlias(true);
            canvas.drawPath(drawShapePath(), paint);
            float[] marginPath;

            final int listSize = mList.size();
            switch (listSize) {
                case 1:
                    startDraw(canvas, mList.get(0), DrawPosition.WHOLE);
                    break;
                case 2:
                    startDraw(canvas, mList.get(0), DrawPosition.LEFT);
                    startDraw(canvas, mList.get(1), DrawPosition.RIGHT);
                    marginPath = new float[]{mWidth / 2, 0, mWidth / 2, mHeight};
                    drawMarginLine(canvas, marginPath);
                    break;
                case 3:
                    startDraw(canvas, mList.get(0), DrawPosition.LEFT);
                    startDraw(canvas, mList.get(1), DrawPosition.RIGHT_TOP);
                    startDraw(canvas, mList.get(2), DrawPosition.RIGHT_BOTTOM);
                    marginPath = new float[]{mWidth / 2, 0,
                            mWidth / 2, mHeight,
                            mWidth / 2, mHeight / 2,
                            mWidth, mHeight / 2};
                    drawMarginLine(canvas, marginPath);
                    break;
                default:
                    startDraw(canvas, mList.get(0), DrawPosition.LEFT_TOP);
                    startDraw(canvas, mList.get(1), DrawPosition.LEFT_BOTTOM);
                    startDraw(canvas, mList.get(2), DrawPosition.RIGHT_TOP);
                    startDraw(canvas, mList.get(3), DrawPosition.RIGHT_BOTTOM);
                    marginPath = new float[]{mWidth / 2, 0,
                            mWidth / 2, mHeight,
                            0, mHeight / 2,
                            mWidth, mHeight / 2};
                    drawMarginLine(canvas, marginPath);
                    break;
            }
            // 仅方形支持边缘  且单个文字不支持边缘
            if (hasEdge && mShape == Shape.SQUARE && !(mList.size() == 1 && mList.get(0) instanceof String)) {
                drawEdge(canvas);
            }

            return result;
        }

        /**
         * 根据边角配置绘制画布path
         */
        private Path drawShapePath() {
            Path mPath = new Path();
            switch (mShape) {
                case Shape.ROUND:
                    mPath.addRoundRect(new RectF(0, 0, mHeight, mWidth), mRoundAngel, mRoundAngel, Path.Direction.CCW);
                    break;
                case Shape.SQUARE:
                    mPath.addRect(new RectF(0, 0, mHeight, mWidth), Path.Direction.CCW);
                    break;
                case Shape.CIRCLE:
                    int radius = Math.max(mWidth, mHeight) / 2;
                    mPath.addCircle(mWidth / 2, mHeight / 2, radius, Path.Direction.CCW);
                    break;
            }

            return mPath;
        }

        /**
         * 根据数据源类型区分绘制图片或文字
         */
        private void startDraw(Canvas canvas, Object resource, int position) {
            if (resource instanceof Bitmap) {
                drawBitmap(canvas, (Bitmap) resource, position);
            } else if (resource instanceof String) {
                drawText(canvas, (String) resource, position);
            }
        }

        /**
         * 绘制图片
         * 最多支持四张图
         */
        private void drawBitmap(Canvas canvas, Bitmap bitmap, int mode) {

            int left, top;
            int x, y, width, height;
            int dstWidth, dstHeight;

            Paint paint = new Paint();
            paint.setAntiAlias(true);
            paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));

            if (mode == DrawPosition.WHOLE) {
                // 比例缩放
                Bitmap bmp = Bitmap.createScaledBitmap(bitmap, mWidth, mHeight, false);
                canvas.drawBitmap(bmp, 0, 0, paint);
            } else if (mode == DrawPosition.LEFT) {
                dstWidth = mWidth;
                dstHeight = mHeight;

                x = mWidth / 4 + mMarginWidth / 4;
                y = 0;
                width = mWidth / 2 - mMarginWidth / 4;
                height = mHeight;

                left = 0;
                top = 0;

                // 比例缩放
                Bitmap bmp = Bitmap.createScaledBitmap(bitmap, dstWidth, dstHeight, false);
                // 裁取中间部分(从x点裁取置顶距离)
                Bitmap dstBmp = Bitmap.createBitmap(bmp, x, y, width, height);
                // 绘图
                canvas.drawBitmap(dstBmp, left, top, paint);
            } else if (mode == DrawPosition.RIGHT) {
                dstWidth = mWidth;
                dstHeight = mHeight;

                x = mWidth / 4 + mMarginWidth / 4;
                y = 0;
                width = mWidth / 2 - mMarginWidth / 4;
                height = mHeight;

                left = mWidth / 2 + mMarginWidth / 4;
                top = 0;

                // 比例缩放
                Bitmap bmp = Bitmap.createScaledBitmap(bitmap, dstWidth, dstHeight, false);
                // 裁取中间部分(从x点裁取置顶距离)
                Bitmap dstBmp = Bitmap.createBitmap(bmp, x, y, width, height);
                // 绘图
                canvas.drawBitmap(dstBmp, left, top, paint);
            } else if (mode == DrawPosition.LEFT_TOP) {
                dstWidth = mWidth / 2 - mMarginWidth / 4;
                dstHeight = mHeight / 2 - mMarginWidth / 4;

                left = 0;
                top = 0;

                // 比例缩放
                Bitmap bmp = Bitmap.createScaledBitmap(bitmap, dstWidth, dstHeight, false);
                // 绘图
                canvas.drawBitmap(bmp, left, top, paint);
            } else if (mode == DrawPosition.LEFT_BOTTOM) {
                dstWidth = mWidth / 2 - mMarginWidth / 4;
                dstHeight = mHeight / 2 - mMarginWidth / 4;

                left = 0;
                top = mHeight / 2 + mMarginWidth / 4;

                // 比例缩放
                Bitmap bmp = Bitmap.createScaledBitmap(bitmap, dstWidth, dstHeight, false);
                // 绘图
                canvas.drawBitmap(bmp, left, top, paint);
            } else if (mode == DrawPosition.RIGHT_TOP) {
                dstWidth = mWidth / 2 - mMarginWidth / 4;
                dstHeight = mHeight / 2 - mMarginWidth / 4;

                left = mWidth / 2 + mMarginWidth / 4;
                top = 0;

                // 比例缩放
                Bitmap bmp = Bitmap.createScaledBitmap(bitmap, dstWidth, dstHeight, false);
                // 绘图
                canvas.drawBitmap(bmp, left, top, paint);
            } else if (mode == DrawPosition.RIGHT_BOTTOM) {
                dstWidth = mWidth / 2 - mMarginWidth / 4;
                dstHeight = mHeight / 2 - mMarginWidth / 4;

                left = mWidth / 2 + mMarginWidth / 4;
                top = mHeight / 2 + mMarginWidth / 4;

                // 比例缩放
                Bitmap bmp = Bitmap.createScaledBitmap(bitmap, dstWidth, dstHeight, false);
                // 绘图
                canvas.drawBitmap(bmp, left, top, paint);
            }
        }

        /**
         * 绘制文字
         */
        private void drawText(Canvas canvas, String text, int mode) {
            float bgLeft = 0, bgTop = 0, bgRight = 0, bgBottom = 0;
            float textSize = mTextSize;

            Paint textBgPaint = new Paint();
            textBgPaint.setColor(ContextCompat.getColor(mContext, mBackGroundColor));
            textBgPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
            if (mode == DrawPosition.WHOLE) {
                bgLeft = 0;
                bgTop = 0;
                bgRight = mWidth;
                bgBottom = mHeight;
                textSize = mWidth / 2;
            } else if (mode == DrawPosition.LEFT) {
                bgLeft = 0;
                bgTop = 0;
                bgRight = mWidth / 2 - mMarginWidth / 4;
                bgBottom = mHeight;
                textSize = mWidth / 4;
            } else if (mode == DrawPosition.RIGHT) {
                bgLeft = mWidth / 2 + mMarginWidth / 4;
                bgTop = 0;
                bgRight = mWidth;
                bgBottom = mHeight;
                textSize = mWidth / 4;
            } else if (mode == DrawPosition.LEFT_TOP) {
                bgLeft = 0;
                bgTop = 0;
                bgRight = mWidth / 2 - mMarginWidth/ 4;
                bgBottom = mHeight / 2 - mMarginWidth/ 4;
                textSize = mWidth / 5;
            } else if (mode == DrawPosition.LEFT_BOTTOM) {
                bgLeft = 0;
                bgTop = mHeight / 2 + mMarginWidth/ 4;
                bgRight = mWidth / 2 - mMarginWidth/ 4;
                bgBottom = mHeight;
                textSize = mWidth / 5;
            } else if (mode == DrawPosition.RIGHT_TOP) {
                bgLeft = mWidth / 2 + mMarginWidth/ 4;
                bgTop = 0;
                bgRight = mWidth;
                bgBottom = mHeight / 2 - mMarginWidth/ 4;
                textSize = mWidth / 5;
            } else if (mode == DrawPosition.RIGHT_BOTTOM) {
                bgLeft = mWidth / 2 + mMarginWidth/ 4;
                bgTop = mHeight / 2 + mMarginWidth/ 4;
                bgRight = mWidth;
                bgBottom = mHeight;
                textSize = mWidth / 5;
            }

            RectF rect = new RectF(bgLeft, bgTop, bgRight, bgBottom);
            canvas.drawRect(rect, textBgPaint);

            Paint textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
            textPaint.setAntiAlias(true);
            textPaint.setColor(ContextCompat.getColor(mContext, mTextColor));
            textPaint.setTextSize(Math.min(mTextSize, textSize));

            textPaint.setStyle(Paint.Style.FILL);
            textPaint.setTextAlign(Paint.Align.CENTER);
            Paint.FontMetrics fontMetrics = textPaint.getFontMetrics();

            int baseline = (int) ((bgBottom + bgTop - fontMetrics.bottom - fontMetrics.top) / 2);
            canvas.drawText(text, rect.centerX(), baseline, textPaint);
        }

        /**
         * 绘制边缘线
         */
        private void drawEdge(Canvas canvas) {
            Paint edgePaint = new Paint();
            edgePaint.setStrokeWidth(mMarginWidth);
            edgePaint.setStyle(Paint.Style.STROKE);
            edgePaint.setColor(ContextCompat.getColor(mContext, mMarginColor));

            Path mPath = new Path();
            mPath.moveTo(0, 0);
            mPath.lineTo(0, mHeight);
            mPath.lineTo(mWidth, mHeight);
            mPath.lineTo(mWidth, 0);
            mPath.close();

            canvas.drawPath(mPath, edgePaint);
        }

        /**
         * 绘制分割线
         */
        private void drawMarginLine(Canvas canvas, float[] path) {
            Paint marginPaint = new Paint();
            marginPaint.setStrokeWidth(mMarginWidth / 2);
            marginPaint.setColor(ContextCompat.getColor(mContext, mMarginColor));
            canvas.drawLines(path, marginPaint);
        }
    }

    public interface Shape {
        int ROUND = 0X33;
        int CIRCLE = 0X11;
        int SQUARE = 0X22;
    }

    interface DrawPosition {
        int WHOLE = 0;
        int LEFT = 1;
        int RIGHT = 2;
        int LEFT_TOP = 3;
        int LEFT_BOTTOM = 4;
        int RIGHT_TOP = 5;
        int RIGHT_BOTTOM = 6;
    }
}

四、使用

1. 复制该类到项目
2. 调用以下方法
// 注:目标图转换成Bitmap,多Bitmap拼接都放在子线程操作
List<Object> bitmapList = new ArrayList()
bitmapList.add(bitmap)         // 添加图片转换完成的bitmap
bitmapList.add("钱")           // 可添加需展示的文字

Bitmap avatar = AvatarUtil.getBuilder(AvatarActivity.this)
                        .setShape(shape)
                        .setMarginWidth(width)
                        .setRoundAngel(height)
                        .setList(bitmapList)
                        .setTextSize(textSize)            // px
                        .setTextColor(R.color.black)      // 需传入color文件下的颜色值
                        .setBitmapSize(size, size)
                        .setHasEdge(hasEdge)
                        .create();

// 放到主线程
ivAvatar.setImageBitmap(avatar)

可以用rxjava线程切换

五、说明

注:
   1. 拼接最多支持四张,需要更多可自行计算
   2. 尺寸传值(图片尺寸、文字尺寸、间隔尺寸),需外部计算成px
   3. 颜色传值,需传入color文件中的色值,例如R.color.black
上一篇下一篇

猜你喜欢

热点阅读