Android 安卓:动画颜色从一种颜色到另一种颜色的变化

Android 安卓:动画颜色从一种颜色到另一种颜色的变化,android,colors,Android,Colors,假设我有两种颜色,我需要创建一个实时动画,快速地从一种颜色切换到另一种颜色 我试着增加十六进制的颜色,直到达到另一个,但这给了一个非常糟糕的动画,因为它显示了许多不相关的颜色 我正在使用setColorFilter(color,colorfilter)更改imageview的颜色 改变色调会给我最好的视觉效果吗?如果是,如何将其更改为纯色 解决方案: 我通过递归变换色调解决了这个问题 private int hueChange(int c,int deg){ float[] hsv

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

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

我正在使用
setColorFilter(color,colorfilter)
更改imageview的颜色

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

解决方案: 我通过递归变换色调解决了这个问题

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

您可以使用
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);
将动画持续时间设置为400ms



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

解决方案:我通过递归切换色调来解决它

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

使用
ValueAnimator
,将@zed和@Phil的答案结合起来,可以提供一个很好的平滑过渡

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在柱坐标中描述颜色,可以很好地分离颜色属性,并允许在单个轴上平滑过渡。从图中可以看出,沿H、S或V方向移动会在颜色之间产生很好的连续过渡


您可以使用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。

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

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

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

您只需使用API 11(蜂巢)提供的
argbeevaluator

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

ValueAnimator anim = ValueAnimator.ofArgb(color1, color2)

首先,我要感谢@bcorso提供了有关HSV的出色答案和数据

当我使用所提出的算法一段时间后,我有点恼火,因为在这个过程中,它会使颜色从一种颜色转移到另一种颜色,从而接触到不相关的颜色。因此,我最终实现了我自己的愚蠢的简单算法,它使用真实的3D坐标进行插值:


以下代码片段对我来说非常有用。我曾想过使用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();

我试过@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);
}

我发现android源代码中的
argbeevaluator
使用的实现在颜色转换方面做得最好。当使用HSV时,根据这两种颜色,过渡对我来说过多的色调。但这种方法并不适用。如果您试图简单地设置动画,请按照建议使用
argbeevaluator
ValueAnimator

但是,如果您像我一样,希望将转换与一些用户手势或输入传递的其他值联系起来,则
ValueAnimator
没有多大帮助(除非您的目标是API 22及以上版本,在这种情况下,您可以使用该方法)。当目标位于API 22以下时,将在中找到的代码包装到您自己的方法中,如下所示:

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))));
}
公共静态整数插值颜色(浮点分数、整数起始值、整数结束值){
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)(分数*(endA-startA))在ColorUtils中使用blendARGB的最佳方法

esay和最小行代码

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

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

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

这两个方面似乎有很多混淆,所以这里有一张图片直观地描述了这一点。

你试过TransitionDrawable吗?什么颜色?ImageView的背景颜色?ImageView的颜色过滤器的颜色。不,我没有使用TransitionDrawable,因为可绘制的颜色不固定,颜色也不固定。什么意思:deawable不是固定的?使用偏移混合颜色请看我的回答:我不相信它会给我一个美丽的视觉效果效果。我通过改变色调来做到这一点。@ZaidDaba'een从我的经验来看,这确实提供了一种非常吸引人的视觉效果,但是我很高兴你发现了其他适合你的东西。@zed你会将你的解决方案添加为可接受的答案,还是接受这个答案?最好将这个问题标记为已回答,因为它可以保持网站的完整性idy.如果没有ARGB求值(如下所述),这将只是迭代颜色int,在大多数情况下看起来非常糟糕。我认为应该将“ofInt()”替换为“ofArgb()”,而“ofArgb()”需要API 21及以上版本,但对于将颜色从A更改为B的动画来说效果非常好。“ofInt()”对我来说效果很差。你应该用
ValueAnimator
来做这类事情。我已经发布了
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));
});