Анимация изменения цвета фонового изображения на Android

Как вы можете изменить цвет фона на Android?

Например:

У меня есть вид с красным цветом фона. Цвет фона в представлении меняется на синий. Как я могу сделать плавный переход между цветами?

Если это невозможно сделать с представлениями, будет приветствоваться альтернатива.

Ответ 1

Я решил выяснить (довольно хорошее) решение этой проблемы!

Для этого вы можете использовать TransitionDrawable. Например, в файле XML в выпадающей папке вы можете написать что-то вроде:

<?xml version="1.0" encoding="UTF-8"?>
<transition xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- The drawables used here can be solid colors, gradients, shapes, images, etc. -->
    <item android:drawable="@drawable/original_state" />
    <item android:drawable="@drawable/new_state" />
</transition>

Затем в вашем XML для фактического представления вы ссылаетесь на этот TransitionDrawable в атрибуте android:background.

На этом этапе вы можете инициировать переход во встроенной команде, выполнив следующие действия:

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

Или запустите переход в обратном порядке, вызвав:

transition.reverseTransition(transitionTime);

См. Роман ответ для другого решения с использованием API анимации свойств, который не был доступен в момент, когда этот ответ был первоначально опубликован.

Ответ 2

Вы можете использовать новую Property Animation Api для цветной анимации:

int colorFrom = getResources().getColor(R.color.red);
int colorTo = getResources().getColor(R.color.blue);
ValueAnimator colorAnimation = ValueAnimator.ofObject(new ArgbEvaluator(), colorFrom, colorTo);
colorAnimation.setDuration(250); // milliseconds
colorAnimation.addUpdateListener(new AnimatorUpdateListener() {

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

});
colorAnimation.start();

Для обратной совместимости с Android 2.x используйте Девять старых андроидов библиотеки от Джейка Уортона.

Метод getColor устарел в Android M, поэтому у вас есть два варианта:

  • Если вы используете библиотеку поддержки, вам нужно заменить вызовы getColor на:

    ContextCompat.getColor(this, R.color.red);
    
  • если вы не используете библиотеку поддержки, вам необходимо заменить вызовы getColor на:

    getColor(R.color.red);
    

Ответ 3

В зависимости от того, как ваш вид получает свой цвет фона и как вы получаете целевой цвет, есть несколько способов сделать это.

Первые два используют инфраструктуру Android Animation.

Используйте Object Animator, если:

  • В вашем представлении цвет фона определяется как значение argb в XML файле.
  • У вашего представления ранее был установлен цвет view.setBackgroundColor()
  • У вашего представления есть свой фоновый цвет, определенный в чертеже, который НЕ ДЕЛАЕТ определяет любые дополнительные свойства, такие как радиус удара или угол.
  • В вашем представлении есть свой фоновый цвет, определенный в чертеже, и вы хотите удалить любые дополнительные свойства, такие как ударные или угловые радиусы, помните, что удаление дополнительных свойств не будет анимировано.

Аниматор объектов работает, вызывая view.setBackgroundColor, который заменяет определенный drawable, если это не экземпляр ColorDrawable, который он редко бывает. Это означает, что любые дополнительные фоновые свойства из рисунка, такого как ход или углы, будут удалены.

Используйте Value Animator, если:

  • В вашем представлении есть свой фоновый цвет, определенный в drawable, который также устанавливает свойства, такие как радиус штриха или угла И вы хотите изменить его на новый цвет, который определяется во время работы.

Используйте переходный вариант, если:

  • Ваше представление должно переключаться между двумя доступными, которые были определены до развертывания.

У меня были некоторые проблемы с производительностью с помощью переходов, которые выполняются, когда я открываю DrawerLayout, который я не смог решить, поэтому, если вы столкнулись с каким-либо неожиданным заиканием, вы, возможно, столкнулись с той же ошибкой, что и у меня.

Вам нужно будет изменить пример Value Animator, если вы хотите использовать StateLists drawable или LayerLists drawable, иначе он выйдет из строя в строке final GradientDrawable background = (GradientDrawable) view.getBackground();.

Объектный аниматор:

Просмотр определения:

<View
    android:background="#FFFF0000"
    android:layout_width="50dp"
    android:layout_height="50dp"/>

Создайте и используйте ObjectAnimator, как это.

final ObjectAnimator backgroundColorAnimator = ObjectAnimator.ofObject(view,
                                                                       "backgroundColor",
                                                                       new ArgbEvaluator(),
                                                                       0xFFFFFFFF,
                                                                       0xff78c5f9);
backgroundColorAnimator.setDuration(300);
backgroundColorAnimator.start();

Вы также можете загрузить определение анимации из xml с помощью AnimatorInflater, например XMight, в Android objectAnimator animate backgroundColor of Layout

Value Animator:

Просмотр определения:

<View
    android:background="@drawable/example"
    android:layout_width="50dp"
    android:layout_height="50dp"/>

Допустимое определение:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <solid android:color="#FFFFFF"/>
    <stroke
        android:color="#edf0f6"
        android:width="1dp"/>
    <corners android:radius="3dp"/>

</shape>

Создайте и используйте ValueAnimator следующим образом:

final ValueAnimator valueAnimator = ValueAnimator.ofObject(new ArgbEvaluator(),
                                                           0xFFFFFFFF,
                                                           0xff78c5f9);

final GradientDrawable background = (GradientDrawable) view.getBackground();
currentAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

    @Override
    public void onAnimationUpdate(final ValueAnimator animator) {
        background.setColor((Integer) animator.getAnimatedValue());
    }

});
currentAnimation.setDuration(300);
currentAnimation.start();

Переходный чертеж:

Просмотр определения:

<View
    android:background="@drawable/example"
    android:layout_width="50dp"
    android:layout_height="50dp"/>

Допустимое определение:

<?xml version="1.0" encoding="utf-8"?>
<transition xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <shape>
            <solid android:color="#FFFFFF"/>
            <stroke
                android:color="#edf0f6"
                android:width="1dp"/>
            <corners android:radius="3dp"/>
        </shape>
    </item>

    <item>
        <shape>
            <solid android:color="#78c5f9"/>
            <stroke
                android:color="#68aff4"
                android:width="1dp"/>
            <corners android:radius="3dp"/>
        </shape>
    </item>
</transition>

Используйте TransitionDrawable следующим образом:

final TransitionDrawable background = (TransitionDrawable) view.getBackground();
background.startTransition(300);

Вы можете отменить анимацию, вызвав .reverse() в экземпляре анимации.

Есть и другие способы анимации, но эти три, вероятно, являются наиболее распространенными. Обычно я использую ValueAnimator.

Ответ 4

Вы можете создать объектный аниматор. Например, у меня есть targetView, и я хочу изменить цвет фона:

int colorFrom = Color.RED;
int colorTo = Color.GREEN;
int duration = 1000;
ObjectAnimator.ofObject(targetView, "backgroundColor", new ArgbEvaluator(), colorFrom, colorTo)
    .setDuration(duration)
    .start();

Ответ 5

Если вам нужна цветная анимация, как эта,

Enter image description here

этот код поможет вам:

ValueAnimator anim = ValueAnimator.ofFloat(0, 1);   
anim.setDuration(2000);

float[] hsv;
int runColor;
int hue = 0;
hsv = new float[3]; // Transition color
hsv[1] = 1;
hsv[2] = 1;
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

    @Override
    public void onAnimationUpdate(ValueAnimator animation) {

        hsv[0] = 360 * animation.getAnimatedFraction();

        runColor = Color.HSVToColor(hsv);
        yourView.setBackgroundColor(runColor);
    }
});

anim.setRepeatCount(Animation.INFINITE);

anim.start();

Ответ 6

Другим простым способом добиться этого является выполнение затухания с использованием AlphaAnimation.

  • Сделайте вид ViewGroup
  • Добавьте дочерний вид к нему с индексом 0, с параметрами макета match_parent
  • Дайте вашему ребенку тот же фон, что и контейнер
  • Изменить на фон контейнера на целевой цвет
  • Затушить ребенка с помощью AlphaAnimation.
  • Удалить анимацию после завершения анимации (используя AnimationListener)

Ответ 7

Лучший способ - использовать ValueAnimator и ColorUtils.blendARGB

 ValueAnimator valueAnimator = ValueAnimator.ofFloat(0.0f, 1.0f);
 valueAnimator.setDuration(325);
 valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator valueAnimator) {

              float fractionAnim = (float) valueAnimator.getAnimatedValue();

              view.setBackgroundColor(ColorUtils.blendARGB(Color.parseColor("#FFFFFF")
                                    , Color.parseColor("#000000")
                                    , fractionAnim));
        }
});
valueAnimator.start();

Ответ 8

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

    protected void setPageBackground(View root, int type){
        if (root!=null) {
            Drawable currentBG = root.getBackground();
            //add your own logic here to determine the newBG 
            Drawable newBG = Utils.createGradientDrawable(type); 
            if (currentBG==null) {
                if(Build.VERSION.SDK_INT<Build.VERSION_CODES.JELLY_BEAN){
                    root.setBackgroundDrawable(newBG);
                }else{
                    root.setBackground(newBG);
                }
            }else{
                TransitionDrawable transitionDrawable = new TransitionDrawable(new Drawable[]{currentBG, newBG});
                transitionDrawable.setCrossFadeEnabled(true);
                if(Build.VERSION.SDK_INT<Build.VERSION_CODES.JELLY_BEAN){
                     root.setBackgroundDrawable(transitionDrawable);
                }else{
                    root.setBackground(transitionDrawable);
                }
                transitionDrawable.startTransition(400);
            }
        }
    }

update: В случае, если кто-то работает с той же проблемой, я обнаружил, что по какой-то причине Android < 4.3 с использованием setCrossFadeEnabled(true) вызывает нежелательный эффект белого, поэтому мне пришлось переключиться на сплошной цвет для < 4.3, использу метод @Roman Minenok ValueAnimator, отмеченный выше.

Ответ 9

Ответ дается во многих отношениях. Вы также можете использовать ofArgb(startColor,endColor) из ValueAnimator.

для API> 21:

int cyanColorBg = ContextCompat.getColor(this,R.color.cyan_bg);
int purpleColorBg = ContextCompat.getColor(this,R.color.purple_bg);

ValueAnimator valueAnimator = ValueAnimator.ofArgb(cyanColorBg,purpleColorBg);
        valueAnimator.setDuration(500);
        valueAnimator.setInterpolator(new LinearInterpolator());
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
              @Override
              public void onAnimationUpdate(ValueAnimator valueAnimator) {
                   relativeLayout.setBackgroundColor((Integer)valueAnimator.getAnimatedValue());
              }
        });
        valueAnimator.start();

Ответ 10

Вот хорошая функция, которая позволяет это:

public static void animateBetweenColors(final View viewToAnimateItBackground, final int colorFrom, final int colorTo,
        final int durationInMs) {
    final ValueAnimator colorAnimation = ValueAnimator.ofObject(new ArgbEvaluator(), colorFrom, colorTo);
    colorAnimation.addUpdateListener(new AnimatorUpdateListener() {
        ColorDrawable colorDrawable = new ColorDrawable(colorFrom);

        @Override
        public void onAnimationUpdate(final ValueAnimator animator) {
            colorDrawable.setColor((Integer) animator.getAnimatedValue());
            viewToAnimateItBackground.setBackgroundDrawable(colorDrawable);
        }
    });
    if (durationInMs >= 0)
        colorAnimation.setDuration(durationInMs);
    colorAnimation.start();
}

Ответ 11

добавьте папку аниматора в папку res. (имя должно быть аниматором). Добавьте файл ресурсов аниматора. Например, res/animator/fade.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <objectAnimator
        android:propertyName="backgroundColor"
        android:duration="1000"
        android:valueFrom="#000000"
        android:valueTo="#FFFFFF"
        android:startOffset="0"
        android:repeatCount="-1"
        android:repeatMode="reverse" />
</set>

Внутри Java файла Activity, позвоните по этому

View v = getWindow().getDecorView().findViewById(android.R.id.content);
AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(this, R.animator.fade);
set.setTarget(v);
set.start();

Ответ 12

Я обнаружил, что реализация, используемая 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))));
}

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

Ответ 13

Документация по анимации на основе XML ужасна. Я искал около часа, чтобы анимировать цвет фона кнопки при нажатии... Печально то, что анимация находится всего в одном атрибуте: вы можете использовать exitFadeDuration в selector:

<selector xmlns:android="http://schemas.android.com/apk/res/android"
    android:exitFadeDuration="200">

    <item android:state_pressed="true">
        <shape android:tint="#3F51B5" />
    </item>

    <item>
        <shape android:tint="#F44336" />
    </item>

</selector>

Тогда просто используйте его как background для вашего обзора. Код Java/Kotlin не требуется.