回声的千结百绕
而守候的是
执着
一仓央嘉措
这篇是自定义LoadingView大全的第四篇博客,也是写得最累最费心费脑的一篇博客,我现在眼睛还疲惫的难受。作为一名程序猿,我在表达能力方面比较欠缺,我希望我能够把它讲清楚。在讲解的过程当中我都会配以图片加以说明。
上图吧:
第一次看到这样的效果,是不是让你眼前一亮,格逼一下就上去了。你可能会问,实现起来会不会很难啊,可以明确的说实现不难,需要你有足够的耐心。
在开始动手写代码之前,我习惯会去先分析转动的立方体该怎么去绘制和添加动画。先来看看下面这张示意图:
先来看看大的立方体,它是由9个面组成,分成了三个阶段。
第一阶段:从A运动到B
数字标出1,2,3,4,5左上运动,每个点的X,Y都在减少;6,7,8,9右下运动,每个点的X,Y坐标都在增大。左右两边长的立方体总共运动了菱形的一个边长,那么可以知道每个长的立方体运动了边长的二分之一。
第二阶段:从B运动到C
1,2面右上运动,每个点的X坐标增大,Y减少;3,4,5,6面没有运动;7,8,9面左下运动,X坐标减少,Y增大。如果把1,2面看成一个立方体则运动了一个菱形的边长。7,8,9面同理。
第三阶段:从C运动到A
3,4,5,7,8,9面左上运动X,Y坐标都在减少;1,2,6面右下运动X,Y都在增大且运动了半个菱形的边长。
比较复杂的是需要去绘制大的立方体A,可以把A分离成9个面,绘制每个面,那么我们先来分析一个面:
设定a为30°,对应的三角形高度为h,那么另一条长度为√3h(根号)。
把A画到坐标系上,如图:
这样是不是就很明了,我们只需要知道中心点坐标,h的长度就可以画出A(大的立方体)。OK,只要画出A,后面的就简单了。
获取中心点坐标以及h的长度:
centerX = w / 2;
mWidth = Math.min(w, h);
//平行四边形的最小角度为30度
mItemWidth = mWidth / 16 * (float) Math.sqrt(3);
mItemHeight = mWidth / 16;
在ondraw方法中处理不同阶段的绘制:
if (mValueAnimator >= 0 && mValueAnimator < (1.0f / 3)) {
//绘制第一阶段
drawStage1(canvas, mValueAnimator);
if (mShadow) {
drawShadow1(canvas, mValueAnimator);
}
} else if (mValueAnimator >= (1.0f / 3) && mValueAnimator < (1.0f / 3 * 2)) {
//绘制第二阶段
drawStage2(canvas, mValueAnimator);
if (mShadow) {
drawShadow2(canvas, mValueAnimator);
}
} else if (mValueAnimator >= (1.0f / 3 * 2) && mValueAnimator <= 1.0f) {
//绘制第三阶段
drawStage3(canvas, mValueAnimator);
if (mShadow) {
drawShadow3(canvas, mValueAnimator);
}
}
mValueAnimator 取值(0.0f~1.0f);mShadow是否显示阴影。
第一阶段绘制:
//这里2个立方体都在移动,每个立方体在X轴方向移动的距离为mItemWidth/2
float moveX = mItemWidth / 2.0f * valueAnimator / (1.0f / 3);
float moveY = mItemHeight / 2.0f * valueAnimator / (1.0f / 3);
//顺时针绘制平行四边形
//向后移动在X 方向 减少 Y方向减少
Path p = new Path();
p.moveTo(centerX - 2 * mItemWidth - moveX, 4 * mItemHeight - moveY);
p.lineTo(centerX - mItemWidth - moveX, 3 * mItemHeight - moveY);
p.lineTo(centerX - moveX, 4 * mItemHeight - moveY);
p.lineTo(centerX - mItemWidth - moveX, 5 * mItemHeight - moveY);
p.close();
canvas.drawPath(p, mPaint);
//向后移动在X 方向 减少 Y方向减少
p.reset();
p.moveTo(centerX - 2 * mItemWidth - moveX, 4 * mItemHeight - moveY);
p.lineTo(centerX - mItemWidth - moveX, 5 * mItemHeight - moveY);
p.lineTo(centerX - mItemWidth - moveX, 7 * mItemHeight - moveY);
p.lineTo(centerX - 2 * mItemWidth - moveX, 6 * mItemHeight - moveY);
p.close();
canvas.drawPath(p, mPaintLeft);
//向前移动在X 方向 X方向增加 Y方向增加
p.reset();
p.moveTo(centerX + moveX, 4 * mItemHeight + moveY);
p.lineTo(centerX - mItemWidth + moveX, 3 * mItemHeight + moveY);
p.lineTo(centerX + moveX, 2 * mItemHeight + moveY);
p.lineTo(centerX + mItemWidth + moveX, 3 * mItemHeight + moveY);
p.close();
canvas.drawPath(p, mPaint);
//向前移动在X 方向 X方向增加 Y方向增加
p.reset();
p.moveTo(centerX + moveX, 4 * mItemHeight + moveY);
p.lineTo(centerX + mItemWidth + moveX, 3 * mItemHeight + moveY);
p.lineTo(centerX + 2 * mItemWidth + moveX, 4 * mItemHeight + moveY);
p.lineTo(centerX + mItemWidth + moveX, 5 * mItemHeight + moveY);
p.close();
canvas.drawPath(p, mPaint);
//向前移动在X 方向 X方向增加 Y方向增加
p.reset();
p.moveTo(centerX + moveX, 4 * mItemHeight + moveY);
p.lineTo(centerX + mItemWidth + moveX, 5 * mItemHeight + moveY);
p.lineTo(centerX + mItemWidth + moveX, 7 * mItemHeight + moveY);
p.lineTo(centerX + moveX, 6 * mItemHeight + moveY);
p.close();
canvas.drawPath(p, mPaintLeft);
//向前移动在X 方向 X方向增加 Y方向增加
p.reset();
p.moveTo(centerX + mItemWidth + moveX, 5 * mItemHeight + moveY);
p.lineTo(centerX + 2 * mItemWidth + moveX, 4 * mItemHeight + moveY);
p.lineTo(centerX + 2 * mItemWidth + moveX, 6 * mItemHeight + moveY);
p.lineTo(centerX + mItemWidth + moveX, 7 * mItemHeight + moveY);
p.close();
canvas.drawPath(p, mPaintRight);
//向后移动在X 方向 减少 Y方向减少
p.reset();
p.moveTo(centerX - mItemWidth - moveX, 5 * mItemHeight - moveY);
p.lineTo(centerX - moveX, 4 * mItemHeight - moveY);
p.lineTo(centerX + mItemWidth - moveX, 5 * mItemHeight - moveY);
p.lineTo(centerX - moveX, 6 * mItemHeight - moveY);
p.close();
canvas.drawPath(p, mPaint);
//向后移动在X 方向 减少 Y方向减少
p.reset();
p.moveTo(centerX - mItemWidth - moveX, 5 * mItemHeight - moveY);
p.lineTo(centerX - moveX, 6 * mItemHeight - moveY);
p.lineTo(centerX - moveX, 8 * mItemHeight - moveY);
p.lineTo(centerX - mItemWidth - moveX, 7 * mItemHeight - moveY);
p.close();
canvas.drawPath(p, mPaintLeft);
//向后移动在X 方向 减少 Y方向减少
p.reset();
p.moveTo(centerX - moveX, 6 * mItemHeight - moveY);
p.lineTo(centerX + mItemWidth - moveX, 5 * mItemHeight - moveY);
p.lineTo(centerX + mItemWidth - moveX, 7 * mItemHeight - moveY);
p.lineTo(centerX - moveX, 8 * mItemHeight - moveY);
p.close();
canvas.drawPath(p, mPaintRight);
在代码中我对每个面的变化都有相应的注释,应该都是可以看懂的。
绘制一个立方体效果图:
能够绘制立方体的变化,阴影层的绘制就非常简单了。
源码地址,如果你喜欢就给我star,再次感谢大家的关注。
自定义LoadingView大全