上篇文章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