Анимировать изменение цвета фона на Android

Как вы анимировать изменение цвета фона представления на Android?

например:

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

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

12 ответов


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

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

<?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 в .

на этом этапе вы можете инициировать переход в вашем коде по команде делать:

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

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

transition.reverseTransition(transitionTime);

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


вы можете использовать new Свойство Анимации 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);
    

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

первые два использует Анимация Свойств Android основы.

использовать Объект Аниматор если:

  • ваш вид имеет свой цвет фона, определенный как argb значение в xml-файле.
  • ваш вид ранее имел свой цвет, установленный view.setBackgroundColor()
  • ваш вид имеет свой цвет фона, определенный в drawable, что НЕ определяет любые дополнительные свойства, такие как ход или угловые радиусы.
  • ваш вид имеет свой цвет фона, определенный в drawable, и вы хотите удалить любые дополнительные свойства, такие как штрихи или угловые радиусы, имейте в виду, что удаление дополнительных свойств не будет анимировано.

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

использовать Аниматор Значение если:

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

использовать a переход drawable если:

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

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

вам придется изменить пример аниматора значений, если вы хотите использовать выигрышного StateLists или 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 анимировать фон макета

Аниматор Значение:

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

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

Drawable определение:

<?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();

переход drawable:

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

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

Drawable определение:

<?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.


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

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

Если вы хотите цветную анимацию, как это,

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

еще один простой способ достичь этого-выполнить переход через AlphaAnimation.

  1. сделайте свой вид ViewGroup
  2. добавьте дочернее представление к нему по индексу 0 с размерами макета match_parent
  3. дайте вашему ребенку тот же фон, что и контейнер
  4. изменить фон контейнера на целевой цвет
  5. выцветание ребенка с помощью AlphaAnimation.
  6. удалите ребенка, когда анимация будет завершена (с помощью AnimationListener)

Это метод, который я использую в базовой активности для изменения фона. Я использую 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);
            }
        }
    }

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


лучший способ использовать 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.setColorBackground(ColorUtils.blendARGB(Color.parseColor("#FFFFFF")
                                    , Color.parseColor("#000000")
                                    , fractionAnim));
        }
});
valueAnimator.start();

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

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

ответ дается многими способами. Вы также можете использовать ofArgb(startColor,endColor) of 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();

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

и использовать его, как вы хотите.


добавить папку аниматор на res. (имя должно быть аниматор). Добавьте файл ресурсов аниматора. Например res / аниматор / 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-файла активности, назовите это

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