如何动画渐变? [英] How to animate gradient?

查看:24
本文介绍了如何动画渐变?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何设置从颜色#1 到颜色#2 的渐变动画?类似的东西

我打算将它用作单位的健康栏(因此,它将是一个以绿色开始并以红色结束的动画)

解决方案

在谷歌搜索时,我发现了 2 种适用于 android 的方法:

诀窍是创建 LinearGradient,它比 View.getWidth()colorsCount 倍.之后,您可以在绘制渐变时使用 canvas.translate() 来更改其颜色,因此在 onDraw() 处没有 new 调用全部.

要创建渐变,您需要当前的宽度和高度.我在 onSizeChanged() 中做到了.我也在这里设置了 Shader.

@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);宽度 = getWidth();高度 = getHeight();LinearGradient 梯度 = 新的 LinearGradient(0,高度/2,宽度*colors.length - 1,高度/2,颜色,空,Shader.TileMode.REPEAT);fillPaint.setShader(渐变);shapePath = getParallelogrammPath(width, height,sidesGap);shapeBorderPath = getParallelogrammPath(width, height,sidesGap);}

我使用路径是因为平行四边形视图,你可以使用任何你想要的.在实现绘图时,您应该注意两件事:您需要在当前偏移上translate()整个 canvasoffset() 您的填充形状:

@Overrideprotected void onDraw(Canvas canvas) {画布.save();canvas.translate(-gradientOffset, 0);shapePath.offset(gradientOffset, 0f, tempPath);canvas.drawPath(tempPath, fillPaint);canvas.restore();canvas.drawPath(shapeBorderPath, borderPaint);super.onDraw(画布);//我的View是FrameLayout,所以需要在之后调用}

你也应该使用 canvas.save() &canvas.restore().它将保存画布内部矩阵堆叠并相应地恢复它.

因此,您需要做的最后一件事是为 gradientOffset 设置动画.你可以使用你想要的一切,比如 ObjectAnimator(属性动画).我使用了 TimeAnimator,因为我需要控制 updateTickcode> 并直接开始偏移.这是我的认识(有点困难和苛刻):

static public final int LIFETIME_DEAFULT = 2300;私人长寿命 = LIFETIME_DEAFULT,updateTickMs = 25,timeElapsed = 0;私人长累加器Ms = 0;私人浮动梯度偏移 = 0f;公共无效 startGradientAnimation() {停止渐变动画();resolveTimeElapsed();final float gradientOffsetCoef = (float) (updateTickMs)/life;final int colorCount = this.colors.length - 1;gradientAnimation.setTimeListener(new TimeAnimator.TimeListener() {@覆盖public void onTimeUpdate(TimeAnimator animation, long totalTime, long deltaTime) {最终长梯度宽度 = 宽度 * 颜色计数;if (totalTime > (lifetime - timeElapsed)) {动画.取消();渐变偏移 = 渐变宽度;无效();} 别的 {accumulatorMs += deltaTime;最终长gradientOffsetsCount = accumulatorMs/updateTickMs;gradientOffset += (gradientOffsetsCount * gradientWidth) * gradientOffsetCoef;accumulatorMs %= updateTickMs;boolean gradientOffsetChanged = (gradientOffsetsCount > 0) ?真假;if (gradientOffsetChanged) {无效();}}}});gradientAnimation.start();}

完整的查看代码,您可以在这里

How to animate gradient from color#1 to color#2? Something similar to

I'm planning to use it as health-bar for unit (so, it will be finit animation starting with green and ending with red)

解决方案

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.

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) :

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.

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);
}

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
}

Also you should use canvas.save() & canvas.restore(). It will save inner matrix of canvas to stack and restore it correspondingly.

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();
}

The full View code you can find here

这篇关于如何动画渐变?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆