自定义LoadingView大全之转动立方体

回声的千结百绕
而守候的是
执着
一仓央嘉措

概述

这篇是自定义LoadingView大全的第四篇博客,也是写得最累最费心费脑的一篇博客,我现在眼睛还疲惫的难受。作为一名程序猿,我在表达能力方面比较欠缺,我希望我能够把它讲清楚。在讲解的过程当中我都会配以图片加以说明。

上图吧:

自定义LoadingView大全之转动立方体_第1张图片

第一次看到这样的效果,是不是让你眼前一亮,格逼一下就上去了。你可能会问,实现起来会不会很难啊,可以明确的说实现不难,需要你有足够的耐心。

具体实现

分析

在开始动手写代码之前,我习惯会去先分析转动的立方体该怎么去绘制和添加动画。先来看看下面这张示意图:

先来看看大的立方体,它是由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个面,绘制每个面,那么我们先来分析一个面:

自定义LoadingView大全之转动立方体_第2张图片

设定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);

在代码中我对每个面的变化都有相应的注释,应该都是可以看懂的。

绘制一个立方体效果图:

自定义LoadingView大全之转动立方体_第3张图片

能够绘制立方体的变化,阴影层的绘制就非常简单了。

源码地址,如果你喜欢就给我star,再次感谢大家的关注。

自定义LoadingView大全

你可能感兴趣的:(android,自定义view,自定义Loading,转动立方体)