如何动画渐变?

Nex*_*xen 12 animation android gradient android-custom-view ondraw

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

在此输入图像描述

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

Nex*_*xen 28

谷歌搜索时,我找到了两种方法来为Android做:使用ShaderFactory或扩展View,使用new Shader(new LinearGradient()).两个答案都是一样的 - 调用new Shader()每个View.onDraw(Canvas canvas)方法的调用.如果这样的动画渐变数超过~3,它真的很贵.

所以我采取了另一种方式.我避免调用new每一个onDraw(),使用一个预先计算LinearGradient.这就是它的样子(gif,所以动画腐烂):

在此输入图像描述

关键是要建立LinearGradientcolorsCount大于倍View.getWidth().之后,您可以canvas.translate()在绘制渐变时使用,以更改其颜色,因此根本不会new调用onDraw().

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

@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);
}
Run Code Online (Sandbox Code Playgroud)

我使用路径因为平行四边形视图,你可以使用你想要的任何东西.在实现绘图时,您应该注意两件事:您需要对当前偏移量和填充形状进行translate()整体canvas处理offset():

@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
}
Run Code Online (Sandbox Code Playgroud)

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

所以最后你需要做的是动画gradientOffset.您可以使用ObjectAnimator(Property Animation)所需的一切.我使用TimeAnimator,因为我需要updateTick直接控制和启动偏移.这是我的认识(有点困难和苛刻):

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();
}
Run Code Online (Sandbox Code Playgroud)

View您可以在此处找到完整的代码

  • @ Chris-Jr,我搜索了很多,没找到我想要的答案.所以我做了一些研究,最后得到了它.然后我想"嗯,也许别人会在将来搜索它并像我一样坚持下去?" - 所以我用答案创建了问题.此外,还有一个内置功能来做到这一点.尝试点击"提问".有一个支票`回答你自己的问题 - 分享你的知识,Q&A风格` (11认同)

Krz*_*tal 10

我已经找到了不同的,更短的方法.随着时间的推移,只需使用它的setColors (int[] colors)方法GradientDrawable和动画.

这是一个如何做到的例子:

val start = Color.DKGRAY
val mid = Color.MAGENTA
val end = Color.BLUE

//content.background is set as a GradientDrawable in layout xml file 
val gradient = content.background as GradientDrawable

val evaluator = ArgbEvaluator()
val animator = TimeAnimator.ofFloat(0.0f, 1.0f)
animator.duration = 1500
animator.repeatCount = ValueAnimator.INFINITE
animator.repeatMode = ValueAnimator.REVERSE
animator.addUpdateListener {
    val fraction = it.animatedFraction
    val newStart = evaluator.evaluate(fraction, start, end) as Int
    val newMid = evaluator.evaluate(fraction, mid, start) as Int
    val newEnd = evaluator.evaluate(fraction, end, mid) as Int

    gradient.colors = intArrayOf(newStart, newMid, newEnd)
}

animator.start()
Run Code Online (Sandbox Code Playgroud)

结果如下:

在此输入图像描述


Csa*_*abi 9

刚刚将@Krzysztof Misztal 的回答改写为java

public static void startAnimation(final int view, final Activity activity) {
        final int start = Color.parseColor("#FDB72B");
        final int mid = Color.parseColor("#88FDB72B");
        final int end = Color.TRANSPARENT;


        final ArgbEvaluator evaluator = new ArgbEvaluator();
        View preloader = activity.findViewById(R.id.gradientPreloaderView);
        preloader.setVisibility(View.VISIBLE);
        final GradientDrawable gradient = (GradientDrawable) preloader.getBackground();

        ValueAnimator animator = TimeAnimator.ofFloat(0.0f, 1.0f);
        animator.setDuration(500);
        animator.setRepeatCount(ValueAnimator.INFINITE);
        animator.setRepeatMode(ValueAnimator.REVERSE);
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                Float fraction = valueAnimator.getAnimatedFraction();
                int newStrat = (int) evaluator.evaluate(fraction, start, end);
                int newMid = (int) evaluator.evaluate(fraction, mid, start);
                int newEnd = (int) evaluator.evaluate(fraction, end, mid);
                int[] newArray = {newStrat, newMid, newEnd};
                gradient.setColors(newArray);
            }
        });

        animator.start();
    }




public static void stopAnimation(final int view, final Activity activity){

    ObjectAnimator.ofFloat(activity.findViewById(view), "alpha", 0f).setDuration(125).start();
}
Run Code Online (Sandbox Code Playgroud)

其中view是一个简单View的渐变背景:

//gradient_preloader
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <gradient
        android:startColor="#FDB72B"
        android:endColor="#00000000"
        android:angle="0"/>
</shape>
Run Code Online (Sandbox Code Playgroud)

风景 :

<View
    android:id="@+id/gradientPreloaderView"
    android:layout_width="match_parent"
    android:visibility="gone"
    android:layout_height="@dimen/basic_8_dp"
    android:background="@drawable/gradient_preloader" />
Run Code Online (Sandbox Code Playgroud)

希望我的回答会有所帮助