android:从颜色到颜色的动画颜色变化
Posted
技术标签:
【中文标题】android:从颜色到颜色的动画颜色变化【英文标题】:android: Animate color change from color to color 【发布时间】:2013-08-15 11:51:01 【问题描述】:假设我有两种颜色,我需要创建一个可以快速从一种颜色切换到另一种颜色的实时动画。
我试图只增加十六进制颜色,直到达到另一个,但这给出了一个非常糟糕的动画,因为它显示了许多不相关的颜色。
我正在使用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);
【问题讨论】:
你尝试过TransitionDrawable吗? 什么颜色? ImageView 的背景? 图像视图的滤色器的颜色。不,我没有使用 TransitionDrawable,因为 drawable 既不是固定的颜色也不是固定的。 什么意思:deawable 没有修复? 要使用偏移来混合颜色,请在此处查看我的答案:***.com/a/24285364/400493 【参考方案1】:结合@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 将提供比 android 的默认颜色空间更好的过渡,因为 HSV 在柱坐标中描述颜色,可以很好地分离颜色的属性并允许在单个轴上平滑过渡。您可以从image below 中看到,沿 H、S 或 V 方向行进会在颜色之间提供很好的连续过渡。
【讨论】:
嗨,如果你有兴趣,这里有一个简单的类,我做了一个让这种颜色插值看起来更自然的类:github.com/konmik/animated-color 请参阅下面的@dimsuz 答案,它为您做了很多工作 这实际上看起来很糟糕,因为例如从蓝色到深灰色的动画会穿过绿色、黄色甚至一些红色。 不知道为什么这被赞成。这样做的效果非常糟糕,就像@vovahost 所说的那样,它会通过其他颜色过渡到目标颜色。例如,如果你从绿色过渡到蓝色,它是绿色 -> 青色 -> 蓝色。对于青色到品红色,它是青色 -> 蓝色 -> 品红色。您可以通过将整数颜色值从源设置为动画来获得更好的效果,如 dimsuz 的回答中所示。 我的猜测是我有更多的赞成票,因为我在另一个答案存在前一年回答了它¯_(ツ)_/¯。我同意,@vovahost 的答案更简单,可能是大多数人想要的。但是,如果您需要手动调整或自定义过渡,这个答案很好,并且图像有助于解释如何做到这一点。【参考方案2】:您可以简单地使用自 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)
【讨论】:
我发现这在这些情况下效果很好。谢谢 如果您不能依赖 API 21 来利用 ofArgb 方法,这将非常有用。谢谢! 奇怪的是,我在过渡期间经历了严重的闪烁,除非我使用这两种颜色:anim.setIntValues(Color.White, Color.yellow)。有什么想法吗? @knutella 我需要在setIntValues(...)
之后调用setEvaluator(...)
以防止闪烁。
@ThomasVos 感谢您的回复。现在工作!【参考方案3】:
您可以使用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。
【讨论】:
我不相信它会给我带来美丽的视觉效果。我设法通过改变色调来做到这一点。 @ZaidDaba'een 根据我的经验,这确实提供了非常吸引人的视觉效果,但我很高兴你找到了其他适合你的东西。 @zed 你会将你的解决方案添加为接受的答案,还是接受这个?最好将此问题标记为已回答,因为这样可以保持网站整洁。 如果没有 ARGB 评估(如下所述),这只会迭代颜色整数,在大多数情况下看起来很糟糕。 我认为您应该将“ofInt()”替换为“ofArgb()”,并且“ofArgb()”需要 API 21 及更高版本,但它非常适用于将颜色从 A 更改为 B 的动画. "ofInt()" 对我来说非常糟糕。【参考方案4】:在 ColorUtils 中使用 blendARGB 的最佳方式。
esay 和最小行代码。
view.setBackgroundColor(ColorUtils.blendARGB(Color.parseColor("#FFFFFF"), Color.parseColor("#CCCCCC"), fraction));
【讨论】:
非常精致漂亮的解决方案!谢谢!【参考方案5】:当转换非常不同的颜色时,其他答案给了我一种奇怪的效果。从黄色到灰色,它会在动画期间的某个时间点变为绿色。
最适合我的是下面的 sn-p。这创造了一个非常平滑的过渡,中间没有出现奇怪的颜色。
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);
【讨论】:
您的blendColors
方法似乎是ArgbEvaluator 的重新实现。
这很好用。我尝试使用 ArgbEvaluator,但由于某种原因它返回分数而不是 arg 值。【参考方案6】:
你可以使用TransitionDrawable
TransitionDrawable transition = (TransitionDrawable) viewObj.getBackground();
transition.startTransition(transitionTime);
在可绘制文件夹中创建 xml 文件,您可以编写如下内容:
<transition xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/end_color" />
<item android:drawable="@drawable/start_color" />
</transition>
然后,在实际 View 的 xml 中,您将在 android:background 属性中引用此 TransitionDrawable。
【讨论】:
您能否在这里提供一个完整的解决方案,说明如何在 android:background 属性中使用它? android:background="@drawable/color_transition" @real19 或以编程方式通过view.setBackground(getResources().getDrawable(drawableId));
。【参考方案7】:
以下 sn-p 非常适合我。我想过使用 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();
【讨论】:
【参考方案8】:我发现ArgbEvaluator
在android 源代码中使用的实现在转换颜色方面做得最好。使用 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))));
随心所欲地使用它。
【讨论】:
【参考方案9】:如果您像我一样尝试从一种 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));
);
这两者似乎有很多混淆,所以这里有一张视觉描述它的图片。
【讨论】:
【参考方案10】:解决方案:我通过递归变换色调解决了这个问题
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
来处理这种类型的事情。我已经发布了关于如何使用 HSV 值执行此操作的答案。【参考方案11】:
我尝试了@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);
【讨论】:
【参考方案12】:首先,我要感谢 @bcorso 提供有关 HSV 的出色答案和数据。
当我使用所提出的算法有一段时间时,我有点恼火,因为它会在此过程中从一种颜色转换为另一种不相关的颜色。所以,我终于实现了自己愚蠢的简单算法,使用真实的 3D 坐标进行插值:
https://github.com/konmik/animated-color
【讨论】:
以上是关于android:从颜色到颜色的动画颜色变化的主要内容,如果未能解决你的问题,请参考以下文章
如何为 UIBezierPath 上的填充颜色变化设置动画?
Android Lollipop 新特性 - Palette