Android圆形头像的绘制(三)之多人头像的实现

本文介绍如何在Android中实现多人圆形头像的自定义控件,支持最多五人的显示。通过创建bean对象存储头像信息,计算每个小圆的位置和旋转角度,最终展示出多人头像的效果。
摘要由CSDN通过智能技术生成

上篇文章Android圆形图像的绘制(二)介绍了单人圆形头像的绘制,这篇文章也是圆形头像的最后一篇。多人头像存在的场景有很多,像一些社交软件,只要涉及到群聊的功能,基本上都会存在多人头像。下面介绍多人头像是怎样实现的,最多支持五人。

在进行多人头像绘制的过程中,CircleImageView自定义控件中应该有个列表保存多人头像的相关信息,每个人的信息应该封装为一个bean对象,上篇文章介绍圆形头像涉及到位图和随机图像的展示,所以我们bean对象包含的数据有位图、随机背景、文本,代码如下:

public class CircleImageViewBean {
    /**
     * 位图
     */
    private Bitmap bitmap;
    /**
     * 随机背景
     */
    private int randomBg;
    /**
     * 文本信息
     */
    private String text;

    public CircleImageViewBean(Bitmap bitmap, int randomBg, String text) {
        this.bitmap = bitmap;
        this.randomBg = randomBg;
        this.text = text;
    }

    public int getRandomBg() {
        return randomBg;
    }

    public void setRandomBg(int randomBg) {
        this.randomBg = randomBg;
    }

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }

    public Bitmap getBitmap() {
        return bitmap;
    }

    public void setBitmap(Bitmap bitmap) {
        this.bitmap = bitmap;
    }
}
在定义好bean对象后,CircleImageView自定义控件应该为外面提供一个公用的方法,方法如下:

    /**
     * 设置多人头像
     * @param circleImageViewBeanList
     */
    public void setImageBitmaps(List<CircleImageViewBean> circleImageViewBeanList) {
        mCircleImageViewBeanList = circleImageViewBeanList;
        invalidate();
    }
接下来看下onDraw方法的实现,代码如下:

    private static final int MAX = 5;

    protected void onDraw(Canvas canvas) {
        //一定要注释掉,否则圆形图像没法生效
//        super.onDraw(canvas);
        if (mWidth > 0 && mHeight > 0) {
//            Bitmap bitmap = createCircleBitmapForSRC_IN(canvas);
//            if (bitmap != null) {
//                canvas.drawBitmap(bitmap, 0, 0, new Paint());
//            }
            if (mCircleImageViewBeanList != null && mCircleImageViewBeanList.size() > 0) {
                mCount = Math.min(mCircleImageViewBeanList.size(), MAX);
                //绘制多人头像
                createCircleBitmap(canvas);
            }
        }
    }

 在绘制之前,需要获取当前多人头像为几人头像,最大值为5,状态用mCount变量保存。下面计算每个小圆相对于大圆的缩放比例,缩放比例的获取用到的是基本的三角函数的相关知识,代码如下: 

    public float getScale(int count) {
        int angle = getAngle(count);
        if (angle == 360) {
            return 1f;
        }
        double cot = getCot(angle);
        float scale = (float) (1f / (Math.sqrt(1 + Math.pow(cot, 2)) + 1));
        return scale;
    }
    private static final int[] sAngleArray = {360, 90, 60, 45, 36};

    private int getAngle(int count) {
        return count > 0 && count <= sAngleArray.length ? sAngleArray[count - 1] : null;
    }
   private double getCot(int angle) {
        double radian = Math.toRadians(angle);
        double sin = Math.sin(radian);
        double cos = Math.cos(radian);
        return  cos / sin;
    }
下面获取与大圆最顶部相切的小圆的左上角位置,主要是为了方便计算其他小圆的左上角的位置,因为找到这个小圆的对应的位置是在旋转角度为零的位置,如果想得到其他小圆的位置,只需要根据旋转角度,运用三角函数知识就可以得到。最上面小圆左上角位置获取的代码如下:
    public float[] getTopPosition(float radius, float scale) {
        float x = radius * (1 - scale);
        float y = 0;
        return new float[] { x, y };
    }

然后,我们获取每个小圆左上角的位置,这里需要知道大圆半径、旋转角度、缩放比例、最上面小圆左上角的位置,旋转角度决定的小头像的摆放位置,它的值定义了一个数据,代码如下:

    private static final float[][] sRotationArray = { new float[] { 360 }, new float[] { 45, -135 },
            new float[] { 120, 0, -120 }, new float[] { 45, 135, -135, -45 },
            new float[] { 144, 72, 0, -72, -144 }};
    public float[] getRotation(int count) {
        return count > 0 && count <= sRotationArray.length ? sRotationArray[count - 1] : null;
    }  

小头像位置计算的代码如下:

  public float[] getTranslatePosition(float radius, float rotation, float scale, float topX, float topY) {
        float smallRadius = radius * (1 - scale);
        double radian = Math.toRadians(rotation);
        double cos = Math.cos(radian);
        double sin = Math.sin(radian);
        float x = (float) (topX - smallRadius * sin);
        float y = (float) (topY + smallRadius * (1 - cos));
        return new float[] { x, y };
    }

得到每个小圆左上角的位置后,需要对目标canvas进行相应的平移,为了能准备画出每个小圆展示在哪个位置,在进行变换之前,需要对目标canvas进行状态的保存,防止这里的变换操作,对其他小圆产生影响,代码如下:

    targetCanvas.save();
    float[] radianPosition = mPresenter.getTranslatePosition(viewSize / 2, rotation[i], scale, topPosition[0], topPosition[1]);
    targetCanvas.translate(radianPosition[0], radianPosition[1]);
    targetCanvas.restore();

当canvas移动到具体的位置之后,我们需要获取位图,将其在canvas上绘制出来。先处理位图相关的绘制逻辑,因为位图的宽高,跟视图的宽高肯定是不一致的,此时需要对位图进行相应的缩放操作,这里涉及到两次缩放的逻辑,第一次是位图缩放到大圆的逻辑,第二次是大圆缩放到小圆的逻辑,代码如下:
    int width = bitmap.getWidth();
    int height = bitmap.getHeight();

    if (width > 0 && height > 0) {
        //对位图进行缩放
        float scaleX = (float) mWidth / width;
        float scaleY = (float) mHeight / height;
        Matrix bitmapMatrix = new Matrix();
        bitmapMatrix.postScale(scaleX, scaleY);
        bitmapMatrix.postConcat(matrix);

        newBitmap = Bitmap.createBitmap(bitmap, 0, 0, width,
                height, bitmapMatrix, true);
    }
随机头像的绘制逻辑跟上篇文章的逻辑基本上是一样的,只是需要注意下,绘制的时候需要在小圆的基础上绘制,需要对字体的大小进行相应的缩放,代码如下:
    int size = (int) (viewSize * scale);

    private Bitmap createRandomMaskBitmap(int size, float scale, String text) {
        Bitma
可生成圆形、方形、及方形的组合头像。项目地址:https://github.com/Pedroafa/avatar-android 效果图:如何使用:首先创建个ImageView<ImageView             android:id="@ id/roundedAvatar"             android:layout_height="fill_parent"             android:layout_width="fill_parent"/>2. //通过AvatarDrawableFactory生成各种形状的Drawable AvatarDrawableFactory avatarDrawableFactory = new AvatarDrawableFactory(getResources()); BitmapFactory.Options options = new BitmapFactory.Options(); options.inMutable = false; Bitmap avatar = BitmapFactory.decodeResource(getResources(), R.drawable.avatar, options); //圆形的 Drawable roundedAvatarDrawable = avatarDrawableFactory.getRoundedAvatarDrawable(avatar);//生成圆形的Drawable ImageView roundedAvatarView = (ImageView)rootView.findViewById(R.id.roundedAvatar); roundedAvatarView.setImageDrawable(roundedAvatarDrawable);其他形状的://圆形的且带边框的 Drawable borderedRoundedAvatarDrawable = avatarDrawableFactory.getBorderedRoundedAvatarDrawable(avatar); ImageView borderedRoundedAvatarView = (ImageView)rootView.findViewById(R.id.borderedRoundedAvatar); borderedRoundedAvatarView.setImageDrawable(borderedRoundedAvatarDrawable); //方形的 Drawable squaredAvatarDrawable = avatarDrawableFactory.getSquaredAvatarDrawable(avatar); ImageView squaredAvatarView = (ImageView)rootView.findViewById(R.id.squaredAvatar); squaredAvatarView.setImageDrawable(squaredAvatarDrawable); //俩个方形的组合头像 Drawable doubleSquaredAvatarDrawable = avatarDrawableFactory.getSquaredAvatarDrawable(avatar, avatar); ImageView doubleSquaredAvatarView = (ImageView)rootView.findViewById(R.id.doubleSquaredAvatar); doubleSquaredAvatarView.setImageDrawable(doubleSquaredAvatarDrawable); //个方形的组合头像 Drawable tripleSquaredAvatarDrawable = avatarDrawableFactory.getSquaredAvatarDrawable(avatar, avatar, avatar); ImageView tripleSquaredAvatarView = (ImageView)rootView.findViewById(R.id.tripleSquaredAvatar); tripleSquaredAvatarView.setImageDrawable(tripleSquaredAvatarDrawable); //四个方形的组合头像 Drawable quadrupleSquaredAvatarDrawable = avatarDrawableFactory                     .getSquaredAvatarDrawable(avatar, avatar, avatar, avatar); ImageView quadrupleSquaredAvatarView = (ImageView)rootView.findViewById(R.id.quadrupleSquaredAvatar); quadrupleSquaredAvatarView.setImageDrawable(quadrupleSquaredAvatarDrawable);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值