android:动画颜色从颜色变为颜色

时间:2013-08-13 18:15:52

标签: android colors

假设我有两种颜色,我需要创建一个可以快速从颜色切换到另一种颜色的实时动画。

我试着增加十六进制的颜色直到我到达另一个,但这给了一个非常糟糕的动画,因为它显示了很多不相关的颜色。

我正在使用setColorFilter(color, colorfilter)来更改图片视图的颜色。

更改HUE会给我最好的视觉效果吗?如果是这样,我如何将其更改为纯色?

解: 我通过递归转移色调来解决它

private int hueChange(int c,int deg){
       float[] hsv = new float[3];       //array to store HSV values
       Color.colorToHSV(c,hsv); //get original HSV values of pixel
       hsv[0]=hsv[0]+deg;                //add the shift to the HUE of HSV array
       hsv[0]=hsv[0]%360;                //confines hue to values:[0,360]
       return Color.HSVToColor(Color.alpha(c),hsv);
    }

12 个答案:

答案 0 :(得分:73)

结合@ zed'和@ Phil的答案,使用ValueAnimator提供了一个很好的平滑过渡。

final float[] from = new float[3],
              to =   new float[3];

Color.colorToHSV(Color.parseColor("#FFFFFFFF"), from);   // from white
Color.colorToHSV(Color.parseColor("#FFFF0000"), to);     // to red

ValueAnimator anim = ValueAnimator.ofFloat(0, 1);   // animate from 0 to 1
anim.setDuration(300);                              // for 300 ms

final float[] hsv  = new float[3];                  // transition color
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener(){
    @Override public void onAnimationUpdate(ValueAnimator animation) {
        // Transition along each axis of HSV (hue, saturation, value)
        hsv[0] = from[0] + (to[0] - from[0])*animation.getAnimatedFraction();
        hsv[1] = from[1] + (to[1] - from[1])*animation.getAnimatedFraction();
        hsv[2] = from[2] + (to[2] - from[2])*animation.getAnimatedFraction();

        view.setBackgroundColor(Color.HSVToColor(hsv));
    }
});

anim.start();                                        

HSV将提供比Androids默认色彩空间更好的过渡,因为HSV描述了圆柱坐标中的颜色,可以很好地分离颜色的属性并允许在单个轴上平滑过渡。您可以从image below看到沿着H,S或V方向行进会在颜色之间产生很好的连续过渡。

enter image description here

答案 1 :(得分:49)

您可以简单地使用自API 11(Honeycomb)以来可用的ArgbEvaluator

ValueAnimator anim = new ValueAnimator();
anim.setIntValues(color1, color2);
anim.setEvaluator(new ArgbEvaluator());
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator valueAnimator) {
        view.setBackgroundColor((Integer)valueAnimator.getAnimatedValue());
    }
});

anim.setDuration(300);
anim.start();

更好的是,从API 21(Lollipop 5.0)开始,您可以将上面代码中的前3行替换为:

ValueAnimator anim = ValueAnimator.ofArgb(color1, color2)

答案 2 :(得分:20)

您可以使用ValueAnimator

//animate from your current color to red
ValueAnimator anim = ValueAnimator.ofInt(view.getBackgroundColor(), Color.parseColor("#FF0000"));
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator animation) {
        view.setBackgroundColor(animation.getAnimatedValue());
    }
});

anim.start();

您还可以在致电anim.start()之前设置持续时间或其他参数。例如:

anim.setDuration(400);

将动画持续时间设置为400毫秒。


最后请注意ValueAnimator Honeycomb 开始可用,因此如果您支持较旧的SDK,则可以使用NineOldAndroids

答案 3 :(得分:11)

其他答案在转换非常不同的颜色时给了我一个奇怪的效果。从黄色到灰色,它会在动画过程中的某个时刻达到绿色。

最适合我的是以下代码段。这创造了一个非常平滑的过渡,中间没有出现奇怪的颜色。

private void changeViewColor(View view) {
    // Load initial and final colors.
    final int initialColor = getResources().getColor(R.color.some_color);
    final int finalColor = getResources().getColor(R.color.another_color);

    ValueAnimator anim = ValueAnimator.ofFloat(0, 1);
    anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            // Use animation position to blend colors.
            float position = animation.getAnimatedFraction();
            int blended = blendColors(initialColor, finalColor, position);

            // Apply blended color to the view.
            view.setBackgroundColor(blended);
        }
    });

    anim.setDuration(500).start();
}

private int blendColors(int from, int to, float ratio) {
    final float inverseRatio = 1f - ratio;

    final float r = Color.red(to) * ratio + Color.red(from) * inverseRatio;
    final float g = Color.green(to) * ratio + Color.green(from) * inverseRatio;
    final float b = Color.blue(to) * ratio + Color.blue(from) * inverseRatio;

    return Color.rgb((int) r, (int) g, (int) b);
}

答案 4 :(得分:8)

您可以使用TransitionDrawable

TransitionDrawable transition = (TransitionDrawable) viewObj.getBackground();
transition.startTransition(transitionTime);

在drawable文件夹中创建xml文件,您可以编写如下内容:

<transition xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/end_color" />
    <item android:drawable="@drawable/start_color" />
</transition>

然后,在你的实际视图的xml中,你将在android:background属性中引用这个TransitionDrawable。

答案 5 :(得分:3)

解决方案:我通过递归转移色调来解决它

private int hueChange(int c,int deg){
       float[] hsv = new float[3];       //array to store HSV values
       Color.colorToHSV(c,hsv); //get original HSV values of pixel
       hsv[0]=hsv[0]+deg;                //add the shift to the HUE of HSV array
       hsv[0]=hsv[0]%360;                //confines hue to values:[0,360]
       return Color.HSVToColor(Color.alpha(c),hsv);
    }

答案 6 :(得分:3)

以下代码段对我来说非常合适。我想过使用ValueAnimator.ofArgb()但是需要最少的api 21.相反,以下适用于api 11及更高版本。它可以顺利实现颜色变化。

ArgbEvaluator evaluator = new ArgbEvaluator();
ValueAnimator animator = new ValueAnimator();
animator.setIntValues(Color.parseColor("#FFFFFF"), Color.parseColor("#000000"));
animator.setEvaluator(evaluator);
animator.setDuration(1000);
//animator.setRepeatCount(ValueAnimator.INFINITE);
//animator.setRepeatMode(ValueAnimator.REVERSE);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            color = (int) animation.getAnimatedValue();
            //postInvalidate(); if you are animating a canvas
            //View.setBackgroundColor(color); another exampleof where to use
        }
    });
animator.start();

答案 7 :(得分:3)

最好的方法是在ColorUtils中使用blendARGB。

esay和最小行代码。

view.setBackgroundColor(ColorUtils.blendARGB(Color.parseColor("#FFFFFF"), Color.parseColor("#CCCCCC"), fraction));

答案 8 :(得分:1)

如果你喜欢我试图从一种RGB颜色变为白色或黑色,你会发现很难使用@ bcorso的答案,因为它对于那个特定的工作来说是错误的色彩空间。不是答案是错的,这不是我所说的。

以下是使用白色(可以用黑色代替)使用颜色colorA进行混合的示例:

float[] from = new float[3];
float[] hsl = new float[3];

ColorUtils.colorToHSL(colorA, from);
float[] to = new float[] {from[0], from[1], 1.0f /* WHITE */};

animator = new ValueAnimator();
animator.setFloatValues(0.0f, 1.0f);
animator.setDuration(1000L);
animator.addUpdateListener(animation -> {
    ColorUtils.blendHSL(from, to, (float) animation.getAnimatedValue(), hsl);

    setColor(ColorUtils.HSLToColor(hsl));
});

这两者似乎有很多混淆,所以这里有一幅描述它的图片。 HSL and HSV

答案 9 :(得分:0)

首先,我要感谢@bcorso提供有关HSV的最佳答案和数据。

虽然我使用所提出的算法已经有一段时间了,但我对它在一个过程中从一种颜色到另一种颜色的颜色转换接触不相关的颜色这一事实感到有些恼火。所以,我最终实现了我自己的愚蠢的简单算法,它使用真实的3D坐标来进行这样的插值:

https://github.com/konmik/animated-color

答案 10 :(得分:0)

我试过@bcorso和@damienix,他们的解决方案对我不起作用。此函数中的数学运算更简单,因为它遵循基本插值公式:

p(t)=(1 - t)* p1 + t * p2,其中t [0,1]

public int interpolateColorFromTo(int currColor, int nextColor, float t) {
    final float[] from = new float[3];
    final float[] to = new float[3];

    Color.colorToHSV(currColor, from);
    Color.colorToHSV(nextColor, to);

    final float[] hsv  = new float[3];
    hsv[0] = (1.0f - t) * from[0] + t * to[0];
    hsv[1] = (1.0f - t) * from[1] + t * to[1];
    hsv[2] = (1.0f - t) * from[2] + t * to[2];

    return Color.HSVToColor(hsv);
}

答案 11 :(得分:0)

我发现android源代码中ArgbEvaluator使用的实现在转换颜色方面做得最好。当使用HSV时,根据两种颜色,过渡对我来说是过多的色调。但这种方法没有。如果您尝试使用ArgbEvaluator按照建议使用ValueAnimator进行简单动画制作here

ValueAnimator colorAnimation = ValueAnimator.ofObject(new ArgbEvaluator(), colorFrom, colorTo);
colorAnimation.addUpdateListener(new AnimatorUpdateListener() { 

    @Override 
    public void onAnimationUpdate(ValueAnimator animator) {
        view.setBackgroundColor((int) animator.getAnimatedValue());
    } 

}); 
colorAnimation.start(); 

但是,如果您像我一样,并希望将转换与某些用户手势或来自输入的其他值相关联,则ValueAnimator没有多大帮助(除非您的目标是API 22及更高版本,在这种情况下,您可以使用ValueAnimator.setCurrentFraction()方法)。在API 22下面定位时,请在您自己的方法中包含ArgbEvaluator source code中的代码,如下所示:

public static int interpolateColor(float fraction, int startValue, int endValue) {
    int startA = (startValue >> 24) & 0xff;
    int startR = (startValue >> 16) & 0xff;
    int startG = (startValue >> 8) & 0xff;
    int startB = startValue & 0xff;
    int endA = (endValue >> 24) & 0xff;
    int endR = (endValue >> 16) & 0xff;
    int endG = (endValue >> 8) & 0xff;
    int endB = endValue & 0xff;
    return ((startA + (int) (fraction * (endA - startA))) << 24) |
            ((startR + (int) (fraction * (endR - startR))) << 16) |
            ((startG + (int) (fraction * (endG - startG))) << 8) |
            ((startB + (int) (fraction * (endB - startB))));
}

并按照您的意愿使用它。