使用场景:
o SplashActivity?
o …
o 好像真的不多 = =
效果看着还可以,有那么几个点一定需要知道实现。
o 粒子效果
o 几个坐标的计算方式
o 文字从左往右像素级显示
只要想清楚以上三点的实现过程,这个动画就没问题了。
一、粒子效果
简单四个字概括:二维数组。
[代码]java代码:
1 2 3 4 5 | private final int ROW_NUM = 10; private final int COLUMN_NUM = 10;
private Particle[][] mParticles = new Particle[ROW_NUM][COLUMN_NUM]; private Particle[][] mMinParticles = new Particle[ROW_NUM][COLUMN_NUM]; |
为何会有两个二维数组?
因为粒子有个从大到小的过程,那么就需要有个起始particle[][]和一个终点particle[][]咯,来看看Particle的结构:
[代码]java代码:
01 02 03 04 05 06 07 08 09 10 11 12 13 14 | public class Particle { public float x; public float y; public float radius;
public Particle() { }
public Particle(float x, float y, float radius) { this.x = x; this.y = y; this.radius = radius; } } |
由x坐标,y坐标和半径构成,那么Particle究竟由起点到终点经过了怎样的转换呢?来看看TypeEvaluator的实现:
[代码]java代码:
01 02 03 04 05 06 07 08 09 10 | public class LineEvaluator implements TypeEvaluator<particle> { @Override public Particle evaluate(float fraction, Particle startValue, Particle endValue) { Particle particle = new Particle(); particle.x = startValue.x + (endValue.x - startValue.x) * fraction; particle.y = startValue.y + (endValue.y - startValue.y) * fraction; particle.radius = startValue.radius + (endValue.radius - startValue.radius) * fraction; return particle; } }</particle> |
就是根据插值进行了一个简单的线性计算。
这样一来由二维数组构成的粒子实现方案已经有了,那么问题来了,动画中那种类似书本翻页的效果是如何实现的呢?
我用了一个很巧妙的方法,那就是对每个粒子设置的Duration都不同。
[代码]java代码:
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 | for (int i = 0; i < ROW_NUM; i++) { for (int j = 0; j < COLUMN_NUM; j++) { final int tempI = i; final int tempJ = j; ValueAnimator animator = ValueAnimator.ofObject(new LineEvaluator(), mParticles[i][j], mMinParticles[i][j]); animator.setDuration(1000 + 20 * i + 30 * j); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { mParticles[tempI][tempJ] = (Particle) animation.getAnimatedValue(); if (tempI == ROW_NUM - 1 && tempJ == COLUMN_NUM - 1) { invalidate(); } } }); animList.add(animator); } } |
关键代码:
[代码]java代码:
1 | animator.setDuration(1000 + 20 * i + 30 * j); |
这样一来,所有粒子同一时间开始,动画的duration不同,那自然类似翻书效果就达到了。
细心的朋友看出来了,我还对粒子做了渐变处理。
[代码]java代码:
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 | Shader linearGradient = new LinearGradient(mWidth / 2 - getTextWidth(mParticleText, mCirclePaint) / 2f, mHeight / 2 - getTextHeight(mParticleText, mCirclePaint) / 2, mWidth / 2 - getTextWidth(mParticleText, mCirclePaint) / 2, mHeight / 2 + getTextHeight(mParticleText, mCirclePaint) / 2, new int[]{mParticleColor, Color.argb(120, getR(mParticleColor), getG(mParticleColor), getB(mParticleColor))}, null, Shader.TileMode.CLAMP); mCirclePaint.setShader(linearGradient);
private int getR(int color) { int r = (color >> 16) & 0xFF; return r; }
private int getG(int color) { int g = (color >> 8) & 0xFF; return g; }
private int getB(int color) { int b = color & 0xFF; return b; } |
二、几个坐标的计算方式
其实做任何动画这一点都尤为重要,整个Canvas都是你的,coordinate那一定得算好。在这个动画里我觉得比较复杂坐标计算的就是最后那个HostText的位移和ParticleText的位移,为什么这么说呢?因为两个Text的textSize不同,但是最终又要保证他俩动画后保持居中。
我用的方案其实很简单,只要精准计算HostText和ParticleText的x坐标就好了,而不用去计算他们各自的偏移量这么复杂。
[代码]java代码:
1 2 3 4 5 | ValueAnimator particleTextXAnim = ValueAnimator.ofFloat(mStartMinP.x + dip2px(4), mWidth / 2 - (getTextWidth(mHostText, mHostTextPaint) + getTextWidth(mParticleText, mParticleTextPaint)) / 2 + getTextWidth(mHostText, mHostTextPaint));
ValueAnimator hostTextXAnim = ValueAnimator.ofFloat(mStartMinP.x, mWidth / 2 - (getTextWidth(mHostText, mHostTextPaint) + getTextWidth(mParticleText, mParticleTextPaint) + dip2px(20)) / 2); |
这两个属性动画的值域很重,各位看官可以仔细看下。
三、文字从左往右像素级显示
这也是此次动画需要解决的最后一个问题,各位朋友可以自己想想咋整。
我这里也是用了一个很巧妙的方式,那就是先drawText,再drawRect进行覆盖,drawRect通过属性动画逐步变小,这样drawText就可以达到像素级的移动效果了。
[代码]java代码:
1 2 | canvas.drawText(mHostText, mHostTextX, mHeight / 2 + getTextHeight(mHostText, mHostBgPaint) / 2, mHostBgPaint); canvas.drawRect(mHostTextX + mHostRectWidth, mHeight / 2 - getTextHeight(mHostText, mHostBgPaint) / 1.2f, mHostTextX + getTextWidth(mHostText, mHostTextPaint), mHeight / 2 + getTextHeight(mHostText, mHostBgPaint) / 1.2f, mHostTextPaint); |
mHostRectWidth是通过属性动画变化的,范围就是0到整个hostText的长度咯。
[代码]java代码:
1 | ValueAnimator animator = ValueAnimator.ofFloat(0, getTextWidth(mHostText, mHostTextPaint)); |
以上就是实现此次粒子动画的关键步骤,其余的相信各位同学看看代码一会就能领悟了。
项目地址:
https://github.com/JeasonWong/Particle
推荐:
共同学习,写下你的评论
评论加载中...
作者其他优质文章