渐变色动画

5

我想要实现的目标:

径向渐变,其起始和结束颜色会平滑地从一个定义的颜色变为另一个。

我尝试过的方法:

使用ObjectAnimator,如下所示:

        searchAnimator = ObjectAnimator.ofFloat(drawThread, new Property<DrawThread, Float>(Float.TYPE, "fraction") {
            @Override
            public Float get(DrawThread object) {
                return object.fraction;
            }

            @Override
            public void set(DrawThread object, Float value) {
                object.setFraction(value);
            }
        }, 0, 1);
        searchAnimator.setDuration(maxSearchDuration);
        searchAnimator.setInterpolator(new LinearInterpolator());

这将随时间调用 DrawThread.setFraction(value);。在线程内,我使用像这样的 SurfaceView 执行 Canvas 绘制:
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setDither(true);
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
radius = (int) Math.sqrt(canvas.getWidth() / 2 * canvas.getWidth() / 2 + canvas.getHeight() / 2 * canvas.getHeight() / 2);
//calculating colors for current fraction using ARGBEvaluator
int start = (int) argbEvaluator.evaluate(fraction, colors[0].start, colors[1].start);
int end = (int) argbEvaluator.evaluate(fraction, colors[0].end, colors[1].end);
//end
mPaint.setShader(new RadialGradient(canvas.getWidth() / 2, canvas.getHeight() / 2,
      radius, start, end, Shader.TileMode.CLAMP));
canvas.drawCircle(canvas.getWidth() / 2, canvas.getHeight() / 2, radius, mPaint);

问题:

  1. 渐变不平滑。图像看起来像低色彩
  2. 性能非常低。在FullHD Snapdragon 801设备上仅获得约16 FPS。

所以我想问的是,是否有任何帮助提高性能(甚至完全不同的方式),并改善结果图像质量的方法。


我可能会尝试将GradientDrawable用作普通视图(而不是SurfaceView)的背景,并使用ValueAnimator在每个动画帧上计算和回调,您可以在其中计算渐变值并调用gradientDrawable.setColors(int[]) - Budius
@Budius,谢谢,但我已经尝试过了。性能相同,并且setColors方法在旧的API(如7)中不可用。 - Vladyslav Matviienko
这将是我的第一种方法,因为它比SurfaceView简单得多。你的后台线程是否在做其他减速工作?关于API级别,不确定您的要求,但API 7太旧了,甚至Google也很久以前停止了对它们的支持。它甚至不显示在仪表板上:https://developer.android.com/about/dashboards/index.html?utm_source=suzunone - Budius
@Budius 这里是 API 文档,其中说明 setColors() 是在 API 16 中添加的。http://developer.android.com/reference/android/graphics/drawable/GradientDrawable.html#setColors(int[])
而且对我来说完全不可能放弃旧版 API 的支持。
- Vladyslav Matviienko
2个回答

1
你可以这样动画渐变中的颜色更改:

您可以像这样动画渐变中的颜色更改:

int colorFrom = ContextCompat.getColor(this, R.color.red);
int colorTo = ContextCompat.getColor(this, R.color.blue);
ValueAnimator colorAnimation = ValueAnimator.ofObject(new ArgbEvaluator(), colorFrom, colorTo);
colorAnimation.setDuration(2000);

int color1 = ContextCompat.getColor(this, R.color.red);
int color2 = ContextCompat.getColor(this, R.color.green);
GradientDrawable gradientDrawable = new GradientDrawable(
            GradientDrawable.Orientation.TOP_BOTTOM, new int[]{color1, color2});
gradientDrawable.setGradientType(GradientDrawable.LINEAR_GRADIENT);

colorAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

        @Override
        public void onAnimationUpdate(ValueAnimator animator) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                gradientDrawable.setColors(new int[]{(int) animator.getAnimatedValue(), color2});
                viewWithGradientBg.setBackground(gradientDrawable);
            }
        }

    });

colorAnimation.start();

Kotlin变量:

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    val colorFrom = ContextCompat.getColor(requireContext(), android.R.color.holo_red_dark)
    val colorTo = ContextCompat.getColor(requireContext(), android.R.color.holo_blue_dark)
    val colorAnimation = ValueAnimator.ofObject(ArgbEvaluator(), colorFrom, colorTo)
    colorAnimation.duration = 2000
    val color1 = ContextCompat.getColor(requireContext(), android.R.color.holo_red_dark)
    val color2 = ContextCompat.getColor(requireContext(), android.R.color.holo_blue_dark)
    val gradientDrawable = GradientDrawable(GradientDrawable.Orientation.TL_BR, intArrayOf(color1, color2))
    gradientDrawable.gradientType = GradientDrawable.RADIAL_GRADIENT
    colorAnimation.addUpdateListener { animator ->
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            gradientDrawable.colors = intArrayOf(animator.animatedValue as Int, color2)
            viewWithGradientBg.background = gradientDrawable
        }
    }
    gradientDrawable.gradientRadius = 140f;
    gradientDrawable.setGradientCenter(0.5f, 0.5f);
    colorAnimation.repeatCount = INFINITE
    colorAnimation.start()
}

您可以在 gradientDrawable.setColors(...) 方法中更改所有颜色。 - Rytis Guntulis
1
这可能有效。我现在无法检查它。我使用了一个解决方法,即通过放置静态透明渐变覆盖在视图上,并更改视图的纯色背景来实现。 - Vladyslav Matviienko
抱歉,请将“RADIAL_GRADIENT”更改为“LINEAR_GRADIENT”。 - Rytis Guntulis
gradientDrawable.gradientRadius = 140f; gradientDrawable.setGradientCenter(0.5f, 0.5f) 无论我输入什么数字,这些变量似乎对渐变没有任何影响。 - AndroidDev123

0

也许这段伪代码能帮到你:

private ValueAnimator colorAnimation;

  colorAnimation = ValueAnimator.ofObject(new ArgbEvaluator(), startColor, endColor); 
                                                          // you can add more colors here 

    colorAnimation.addUpdateListener(new AnimatorUpdateListener() {

        @Override
        public void onAnimationUpdate(ValueAnimator animator) {
            yourView.setBackgroundColor((Integer) animator
                    .getAnimatedValue());
        }

    });

    colorAnimation.setDuration(maxSearchDuration);
    colorAnimation.start();
}

2
在背景上动画单一颜色并不是问题。但是如果你再读一遍我的问题,你会发现问题是如何动画渐变。 - Vladyslav Matviienko

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接