Подтвердить что ты не робот

Андроид: изменение цвета анимации от цвета к цвету

Предполагая, что у меня два цвета, и мне нужно создать анимацию в реальном времени, которая быстро переключается с цвета на другой.

Я пытался просто увеличить шестнадцатеричный цвет до тех пор, пока не дойду до другого, но это дало очень плохую анимацию, так как показало много не связанных цветов.

Я использую 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);
    }
4b9b3361

Ответ 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))));
}

и используйте его, как хотите.