如何动画渐变? [英] How to animate gradient?
问题描述
如何从动画颜色#1梯度颜色#2?类似的东西。
How to animate gradient from color#1 to color#2? Something similar to
我打算把它作为保健栏单元(因此,这将是FINIT动画开始用绿色和红色的结尾)
I'm planning to use it as health-bar for unit (so, it will be finit animation starting with green and ending with red)
推荐答案
在谷歌上搜索,我发现2种方法来做到这一点为Android:的使用ShaderFactory 或扩展视图,使用新的着色器(新的LinearGradient())
。这两个答案做同样的 - 调用新的着色器()
每个 View.onDraw(帆布油画)
方法的调用。它真的很贵,如果这样的动画渐变超过数量〜3。
While googling it, I found 2 ways to do it for android: use ShaderFactory or extends View, using new Shader(new LinearGradient())
. Both answers do the same - calling new Shader()
every View.onDraw(Canvas canvas)
method's call. Its really expensive if number of such animated gradients more than ~3.
所以,我做了另一种方式。我避免调用新
每个的onDraw()
,使用pcalculated单$ P $ 的LinearGradient
。这就是它是什么样子(GIF,所以动画腐烂):
So I did it another way. I avoided calling new
every onDraw()
, using single precalculated LinearGradient
. That's how it is look like (gif, so animation decayed) :
关键是要创建的LinearGradient
是 colorsCount
比 View.getWidth大时代()
。之后,你可以使用 canvas.translate()
,同时提请梯度,以改变其颜色,所以没有新
通话在的onDraw()
的。
The trick is to create LinearGradient
which is colorsCount
times larger than View.getWidth()
. After that you can use canvas.translate()
, while drawing gradient, to change its color, so no new
calls in onDraw()
at all.
要创建渐变,则需要当前的宽度和高度。我这样做是在 onSizeChanged()
。我设立着色
这里。
To create gradient, you need current width and height. I did it in onSizeChanged()
. Also I set Shader
here too.
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
width = getWidth();
height = getHeight();
LinearGradient gradient = new LinearGradient(
0, height / 2, width * colors.length - 1, height / 2,
colors, null, Shader.TileMode.REPEAT);
fillPaint.setShader(gradient);
shapePath = getParallelogrammPath(width, height, sidesGap);
shapeBorderPath = getParallelogrammPath(width, height, sidesGap);
}
我用的,因为parallelogramy意见的路径,你可以使用任何你想要的。当实现绘图,你应该注意到两件事:你需要翻译()
全画布
当前偏移和偏移()
您填充形状:
I use path because of parallelogramy views, you can use whatever you want. When implementing drawing, you should notice 2 things: you need to translate()
whole canvas
on current offset and offset()
your filling shape:
@Override
protected void onDraw(Canvas canvas) {
canvas.save();
canvas.translate(-gradientOffset, 0);
shapePath.offset(gradientOffset, 0f, tempPath);
canvas.drawPath(tempPath, fillPaint);
canvas.restore();
canvas.drawPath(shapeBorderPath, borderPaint);
super.onDraw(canvas); // my View is FrameLayout, so need to call it after
}
此外,你应该使用 canvas.save()
&安培; canvas.restore()
。这将节省帆布内部基质栈和相应的恢复。
Also you should use canvas.save()
& canvas.restore()
. It will save inner matrix of canvas to stack and restore it correspondingly.
所以最后你需要做的是动画 gradientOffset
。你可以使用任何你想要像 ObjectAnimator(属性动画)的一切。我用 TimeAnimator ,因为我需要控制 updateTick
和起始直接抵消。这里是我的实现(有点难度及恶劣):
So the last what you need to do is to animate gradientOffset
. You can use everything you want like ObjectAnimator (Property Animation). I used TimeAnimator, because I needed to control updateTick
and starting offset directly. Here is my realisation (a bit difficult and harsh):
static public final int LIFETIME_DEAFULT = 2300;
private long lifetime = LIFETIME_DEAFULT, updateTickMs = 25, timeElapsed = 0;
private long accumulatorMs = 0;
private float gradientOffset = 0f;
public void startGradientAnimation() {
stopGradientAnimation();
resolveTimeElapsed();
final float gradientOffsetCoef = (float) (updateTickMs) / lifetime;
final int colorsCount = this.colors.length - 1;
gradientAnimation.setTimeListener(new TimeAnimator.TimeListener() {
@Override
public void onTimeUpdate(TimeAnimator animation, long totalTime, long deltaTime) {
final long gradientWidth = width * colorsCount;
if (totalTime > (lifetime - timeElapsed)) {
animation.cancel();
gradientOffset = gradientWidth;
invalidate();
} else {
accumulatorMs += deltaTime;
final long gradientOffsetsCount = accumulatorMs / updateTickMs;
gradientOffset += (gradientOffsetsCount * gradientWidth) * gradientOffsetCoef;
accumulatorMs %= updateTickMs;
boolean gradientOffsetChanged = (gradientOffsetsCount > 0) ? true : false;
if (gradientOffsetChanged) {
invalidate();
}
}
}
});
gradientAnimation.start();
}
完整查看
code,你可以找到<一个href=\"https://github.com/Nexen23/I_am_here/blob/1.2.0/app/src/main/java/alex/imhere/fragment/view/UserLayout.java\"相对=nofollow>这里
The full View
code you can find here
这篇关于如何动画渐变?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!