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

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

问题描述

如何从动画颜色#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屋!

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