为了加强对自定义 View 的认知以及开发能力,我计划这段时间陆续来完成几个难度从易到难的自定义 View,并简单的写几篇博客来进行介绍,所有的代码也都会开源,也希望读者能给个 star 哈
GitHub 地址:https://github.com/leavesC/CustomView
也可以下载 Apk 来体验下:https://www.pgyer.com/CustomView
先看下效果图:
和 QQ邮箱 官方的还是有点差别的,没完成仿造成功,不过大概思路明白了就可以的了~
以左边的小圆作为例子,其变化规律是这样的
- 小圆半径从 0 逐渐增大到 minRadius ,此过程只是半径增大,其坐标点不变,依然处于最左边
- 小圆从左边逐渐位移到中间位置,此过程半径逐渐从 minRadius 增大到 maxRadius,X 坐标逐渐增大,Y 坐标不变
- 小圆从中间逐渐位移到最右边,此过程半径从 maxRadius 逐渐减小到 minRadius,X 坐标逐渐增大,Y 坐标不变
- 小圆处于最右边保持坐标点不变,半径逐渐从 minRadius 减小到 0
三个小圆的变化规律都是如上所述,只是起始状态有所差别而已,可以规定各个状态占总的动画时间的四分之一,因此 CircleRefreshView 的重点就在于根据动画值的变化来计算三个小圆的坐标系以及半径大小
private void updateCircle(int index, float fraction) {
// x x x
// ------------||-------------||--------------||------------
// 1/4 2/4 3/4
// 1/4 2/4 3/4 4/4
// 左边-绿色
// 半径从0到min 半径从min到max 半径从max到min 半径从min到0
// 中间-橙色
// 半径从max到min 半径从min到0
//半径从0到min 半径从min到max
// 右边-红色
// 半径从min到0
//半径从0到min 半径从min到max 半径从max到min
float radius = 0;
float x = 0;
switch (index) {
case LEFT: {
if (fraction <= 1f / 4f) {
radius = minRadius * (4f * fraction);
x = minRadius;
} else if (fraction <= 0.5f) {
float percent = (fraction - 1f / 4f) * 4f;
radius = minRadius + percent * (maxRadius - minRadius);
x = minRadius + percent * (contentWidth / 2f - minRadius);
} else if (fraction <= 3f / 4f) {
float percent = (fraction - 0.5f) * 4f;
radius = maxRadius - percent * (maxRadius - minRadius);
x = contentWidth / 2f + percent * (contentWidth / 2f - minRadius);
} else {
radius = minRadius - (fraction - 3f / 4f) * 4f * minRadius;
x = contentWidth - minRadius;
}
break;
}
case CENTER: {
if (fraction <= 1f / 4f) {
float percent = fraction * 4f;
radius = maxRadius - (maxRadius - minRadius) * percent;
x = contentWidth / 2f + (contentWidth / 2f - minRadius) * percent;
} else if (fraction <= 0.5f) {
radius = minRadius - (fraction - 1f / 4f) * 4f * minRadius;
x = contentWidth - minRadius;
} else if (fraction <= 3f / 4f) {
radius = minRadius * (4f * (fraction - 0.5f));
x = minRadius;
} else {
float percent = (fraction - 3f / 4f) * 4f;
radius = minRadius + (maxRadius - minRadius) * percent;
x = minRadius + (contentWidth / 2f - minRadius) * percent;
}
break;
}
case RIGHT: {
if (fraction <= 1f / 4f) {
radius = minRadius - 4f * fraction * minRadius;
x = contentWidth - minRadius;
} else if (fraction <= 0.5f) {
radius = minRadius * (4f * (fraction - 1f / 4f));
x = minRadius;
} else if (fraction <= 3f / 4f) {
float percent = (fraction - 0.5f) * 4f;
radius = minRadius + (maxRadius - minRadius) * percent;
x = minRadius + (contentWidth / 2f - minRadius) * percent;
} else {
float percent = (fraction - 3f / 4f) * 4f;
radius = maxRadius - (maxRadius - minRadius) * percent;
x = contentWidth / 2f + (contentWidth / 2f - minRadius) * percent;
}
break;
}
}
Circle circle = circleList.get(index);
circle.radius = radius;
circle.x = x;
}
然后在 onDraw 方法里直接绘制三个小圆点即可
@Override
protected void onDraw(Canvas canvas) {
for (Circle circle : circleList) {
paint.setColor(circle.color);
canvas.drawCircle(circle.x + getPaddingLeft(), circle.y + getPaddingTop(), circle.radius, paint);
}
}