Андроид: изменение цвета анимации от цвета к цвету
Предполагая, что у меня два цвета, и мне нужно создать анимацию в реальном времени, которая быстро переключается с цвета на другой.
Я пытался просто увеличить шестнадцатеричный цвет до тех пор, пока не дойду до другого, но это дало очень плохую анимацию, так как показало много не связанных цветов.
Я использую 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);
}
Ответы
Ответ 1
РЕШЕНИЕ: Я решил его рекурсивно меняя оттенок
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);
}
Ответ 2
Объединение ответов @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 описывает цвета в цилиндрических координатах, которые прекрасно разделяют цветовые свойства и обеспечивают плавный переход по одной оси. Вы можете видеть на изображении ниже, что перемещение по направлениям H, S или V дает хороший непрерывный переход между цветами.
![enter image description here]()
Ответ 3
Вы можете просто использовать ArgbEvaluator
, который доступен с API 11 (Honeycomb):
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)
Ответ 4
Вы можете использовать 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.
Ответ 5
Другие ответы дали мне странный эффект при переходе самых разных цветов. От желтого до серого он достигнет зелени в какой-то момент во время анимации.
Что лучше всего для меня было следующим фрагментом. Это создало действительно плавный переход без каких-либо странных цветов, появляющихся между ними.
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);
}
Ответ 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>
Затем в вашем xml для фактического представления вы ссылаетесь на этот TransitionDrawable в атрибуте android: background.
Ответ 7
Следующий фрагмент отлично работал у меня. Я думал об использовании 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
Лучший способ использовать blendARGB в ColorUtils.
и минимальный код строки.
view.setBackgroundColor(ColorUtils.blendARGB(Color.parseColor("#FFFFFF"), Color.parseColor("#CCCCCC"), fraction));
Ответ 9
Во-первых, я хотел бы поблагодарить @bcorso за отличный ответ и данные о HSV.
Пока я использовал предложенный алгоритм в течение некоторого времени, меня слегка раздражало то, что он меняет цвет от одного цвета к другому, касаясь несвязанных цветов в процессе. Итак, я, наконец, реализовал свой собственный глупый простой алгоритм, который использует реальные 3D-координаты для такой интерполяции:
https://github.com/konmik/animated-color
Ответ 10
Я попробовал @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
Я обнаружил, что реализация, используемая ArgbEvaluator
в исходном коде Android, лучше всего подходит для перехода цветов. При использовании HSV, в зависимости от двух цветов, переход проходил через слишком много оттенков для меня. Но эти методы этого не делают. Если вы пытаетесь просто анимировать использование ArgbEvaluator
с ValueAnimator
, как предложено здесь:
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
исходный код в свой собственный метод, как показано ниже:
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))));
}
и используйте его, как хотите.