Andoird自定义View贝塞尔曲线入门用法:仿天猫LOGO加载动画

来源:互联网 发布:java 二进制上传文件 编辑:程序博客网 时间:2024/06/07 19:58

一、前言

打开天猫随便搜索一下,就会出现一个天猫LOGO的加载图
这里写图片描述

模拟效果:
这里写图片描述
gif图的效果不是很好,手机上运行效果比较好。

二、实现思路

先推荐两篇文章了解一下贝塞尔曲线:
http://www.gcssloop.com/customview/Path_Bezier
http://blog.csdn.net/harvic880925/article/details/50995587

可以让美工做一个图,然后转换成SVG,使用一些svg -> path的库转换成Path,再使用动画展示出来。不过这LOGO看上去不是很复杂,就自己绘制,弧度都是使用贝塞尔曲线绘制。
1. 知道photoshop中的钢笔工具是用贝塞尔曲线实现的,那首先用PS来简单构建一个模型,确定控制点坐标。
2. 用path.lineTo、quadTo、cubicTo等方法绘制路径。
3. 用PathMeasure类来截取长度,达到闭合图形的缺口目的。
4. ValueAnimator属性动画,动起来。

三、开始绘制

1.用PS画出草图

经过调整,得到以下:
这里写图片描述

以一个栅格(cell)为基本单位,中心点表示整个图形的中央位置,大概得出整个图形:
长度:12 * cell,高度:8 * cell,为了方便计算和绘制图形,以黑色圆点为坐标原点。
红色原点:坐标点
黄色原点:贝塞尔曲线控制点
p1(cell, 0),p2(5 * cell, -2 * cell),p3(6 * cell, 0),p4(6 * cell,5 * cell),p5(5 * cell, 6 * cell)
c1(3 * cell, 0),c2(4 * cell, -2 * cell),c3(6 * cell, -2 * cell),c4(6 * cell,6 * cell)
左侧和右侧是镜像关系,所以左侧坐标只需要将右侧x坐标取反即可。

2.代码实现

private void initEarsPath() {        p1.x = cellSize ;        p1.y = 0;        p2.x = 5 * cellSize ;        p2.y = -2 * cellSize;        p3.x = 6 * cellSize;        p3.y = 0;        p4.x = 6 * cellSize ;        p4.y = 5 * cellSize ;        p5.x = 5 * cellSize ;        p5.y = 6 * cellSize ;        c1.x = 3 * p1.x ;        c1.y = 0;        c2.x = 4 *cellSize ;        c2.y = -2 * cellSize ;        c3.x = 6 * cellSize;        c3.y = -2 * cellSize ;        c4.x = 6 * cellSize ;        c4.y = 6 * cellSize ;        mPath.moveTo(p1.x, p1.y);        //三阶        mPath.cubicTo(c1.x, c1.y, c2.x,c2.y, p2.x, p2.y);        //二阶        mPath.quadTo(c3.x, c3.y, p3.x, p3.y);        //右侧直线        mPath.lineTo(p4.x, p4.y);        //右下角圆弧        mPath.quadTo(c4.x, c4.y, p5.x, p5.y);        //取反        p1.x = -p1.x;        p2.x = -p2.x;        p3.x = -p3.x;        p4.x = -p4.x;        p5.x = -p5.x;        c1.x = -c1.x;        c2.x = -c2.x;        c3.x = -c3.x;        c4.x = -c4.x;        mPath.lineTo(p5.x, p5.y);        //左下角圆弧        mPath.quadTo(c4.x, c4.y, p4.x, p4.y);        //左侧直线        mPath.lineTo(p3.x, p3.y);        //二阶        mPath.quadTo(c3.x, c3.y, p2.x, p2.y);        //三阶        mPath.cubicTo(c2.x, c2.y, c1.x,c1.y, p1.x, p1.y);        mPath.close();        mMeasure.setPath(mPath, false);        mPathLength = mMeasure.getLength();    }

3.缺口实现
这里写图片描述
将图形展开成一条直线好分析,开始点和终点其实是一个点,图中绿色表示缺口距离,A点加上间距等于B点,有两种情况。
1.A和B正好在线段的中间
2.B经过了终点(始点)而A还没经过终点
根据这两种情况从原path使用PathMeasure截取出红色部分的内容存放在新的path中,再将新的Path绘制出来就实现缺口。

4.动画

private void initListener() {        mAnimator = ValueAnimator.ofFloat(0.0f, 1.0f);        mAnimator.setDuration(2000);//一段path的时间        mAnimator.setRepeatCount(ValueAnimator.INFINITE);//无限循环        //加入线性插值器 计算返回的值均匀递增 如若不用 会出现不连续现象        mAnimator.setInterpolator(new LinearInterpolator());        mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {            @Override            public void onAnimationUpdate(ValueAnimator animation) {                mAnimatorValue = (float) animation.getAnimatedValue();                invalidate();            }        });        mAnimator.start();    }

5.绘制

@Override@Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        canvas.translate(mViewWidth / 2, mViewHeight / 2 - 2 * cellSize);        mDstPath.reset();        //判断哪种缺口情况        if (mPathLength * mAnimatorValue + distance <= mPathLength) {            mMeasure.getSegment(0, mPathLength * mAnimatorValue, mDstPath, true);            mMeasure.getSegment(mPathLength * mAnimatorValue + distance, mPathLength, mDstPath, true);        } else {            mMeasure.getSegment(distance - mPathLength * (1 - mAnimatorValue), mPathLength * mAnimatorValue, mDstPath, true);        }        canvas.drawPath(mDstPath, mPaint);    }

三、总结

本次主要熟悉使用贝塞尔曲线来绘制路径,通过PS来辅助完成坐标点和控制点的选取,以及跟Path相关的类做出动画效果。

源码