Анімована зміна кольору фону на екрані Android


335

Як ви оживляєте зміну кольору фону в режимі перегляду на Android?

Наприклад:

У мене вид з червоним кольором тла. Колір фону перегляду змінюється на синій. Як я можу зробити плавний перехід між кольорами?

Якщо цього неможливо зробити з поглядами, буде запропоновано альтернативу.


11
Можна очікувати, що плавний перехід між кольорами не повинен бути проблемою для такої платформи, як Android. Можливо, погляди для цього не побудовані. Питання досі стоїть.
hpique

Відповіді:


374

Я в кінцевому підсумку з'ясував (досить гарне) рішення цієї проблеми!

Ви можете використовувати TransitionDravable для цього. Наприклад, у 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 атрибут.

У цей момент ви можете ініціювати перехід у своєму коді on-command, виконавши:

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

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

transition.reverseTransition(transitionTime);

Дивіться відповідь Романа на інше рішення за допомогою API анімації властивостей, який не був доступний на момент публікації цієї відповіді.


3
Дякую mxrider! Це відповідає на питання. На жаль, це не працює для мене, тому що перегляд, який має TransitionDravable як фон, повинен бути анімований, і, здається, анімація перегляду перекриває фоновий перехід. Будь-які ідеї?
hpique

6
Вирішили це, запустивши TransitionDravable ПІСЛЯ, починаючи анімацію.
hpique

2
Дивовижно! Радий, що ти це працює! У xml за допомогою Android можна зробити багато цікавих речей - значна частина яких похована в документах і на мою думку не очевидна.
ідолізувати

4
Зовсім не очевидно. Слід зазначити, що в моєму випадку я не використовую xml, оскільки колір динамічний. Ваше рішення також працює, якщо ви створили TransitionDravable за кодом.
hpique

2
Один з головних недоліків - відсутність повного слухача анімації
Leo Droidcoder

511

Ви можете використовувати нову анімацію властивостей 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 використовуйте бібліотеку Nine Old Androids від Jake Wharton.

getColorМетод засуджувався в Android M, так що у вас є два варіанти:

  • Якщо ви користуєтеся бібліотекою підтримки, вам потрібно замінити getColorдзвінки на:

    ContextCompat.getColor(this, R.color.red);
  • якщо ви не використовуєте бібліотеку підтримки, вам потрібно замінити getColorдзвінки на:

    getColor(R.color.red);

2
рішення "musthave", якщо ви використовуєте API анімації властивостей (або NineOldAndroid). Анімує дуже плавно.
Дмитро Зайцев

1
Чи є спосіб встановити тривалість переходу таким чином?
iGio90

159
@ iGio90 так, ви не вірите, але метод виклику setDuration () :)
Роман Міненок

6
ValueAnimator.ofArgb(colorFrom, colorTo)виглядає більше до речі, але, на жаль, це нове.
TWiStErRob

1
Прекрасне рішення! Дякую.
Стів Фоллі

137

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

Перші два використовують анімацію власності Android рамки .

Використовуйте аніматор об'єктів, якщо:

  • Колір тла перегляду визначається як argb значення у файлі xml.
  • Раніше ваш колір перегляду визначав колір view.setBackgroundColor()
  • Колір тла перегляду визначається кольором фонового рисунка, який НЕ визначає додаткових властивостей, таких як радіус обведення або кута.
  • Колір тла перегляду визначається кольором фонового рисунка, і ви хочете видалити будь-які додаткові властивості, наприклад, радіуси обведення або кута, пам’ятайте, що видалення додаткових властивостей не буде анімовано.

Аніматор об'єкта працює за допомогою виклику, view.setBackgroundColorякий замінює визначений графічний малюнок, за винятком випадків ColorDrawable, коли це рідко. Це означає, що будь-які зайві фонові властивості з такого малювання, як штрих або кути будуть видалені

Використовуйте аніматор значення, якщо:

  • Колір тла перегляду визначено кольором фонового рисунка, який також встановлює такі властивості, як радіуси обведення або кута, і ви хочете змінити його на новий колір, який вирішується під час запуску.

Використовуйте перехідну схему, якщо:

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

У мене виникли деякі проблеми з роботою з перетяжками переходу, яка працює під час відкриття DrawerLayout, яку мені не вдалося вирішити, тому, якщо ви зіткнетесь із несподіваним заїканням, ви могли зіткнутися з тією ж помилкою, що і я.

Вам потрібно буде змінити приклад Value Animator, якщо ви хочете використовувати StateLists, що малюється, або LayerLists, що малюється , інакше він вийде з 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Аніматор анімації фонуColor of Layout

Значення аніматора :

Перегляд визначення:

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


насправді можна визначити і використовувати TransitionDravable в коді, але чомусь це не працює вдруге. дивно.
андроїд розробник

Я в змозі використовувати аніматор об'єктів, навіть якщо в моєму вікні встановлено ColorDravable. Я просто зберігаю його в локальній змінній, встановлюю її на нуль, і коли анімація закінчена, повертаю оригінальний ColorDravable назад.
Miloš Černilovský

55

Можна зробити аніматора об’єктів. Наприклад, у мене targetView і я хочу змінити ваш колір тла:

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

2
З API 21 ви можете використовувати ofArgb(targetView, "backgroundColor", colorFrom, colorTo). Її реалізація справедлива ofInt(...).setEvaluator(new ArgbEvaluator()).
ypresto

20

Якщо ви хочете кольорову анімацію, як це,

Введіть тут опис зображення

цей код допоможе вам:

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

9
Де та частина , коли аніме змінна ініціалізується?
VoW

@VoW, це лише екземпляр ValueAnimator.
РБК

Це має бути anim.setRepeatCount(ValueAnimator.INFINITE);не Animation.INFINITE, зараз це те саме, але у нас немає гарантій
MikhailKrishtop

@MikhailKrishtop Що не так з Animation.INFINITE? developer.android.com/reference/android/view/animation/…
RBK

14

найкращим способом є використання 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();

12

Ще один простий спосіб досягти цього - виконати вимкнення, використовуючи AlphaAnimation.

  1. Зробіть свій перегляд ViewGroup
  2. Додайте до нього дочірнє подання в індексі 0, з розмірами макета-прозорого
  3. Дайте дитині такий самий фон, як контейнер
  4. Перейдіть на фон контейнера до цільового кольору
  5. Зникає дитина за допомогою AlphaAnimation.
  6. Видаліть дитину, коли анімація завершена (за допомогою програми AnimationListener)

9

Це метод, який я використовую в базовій діяльності для зміни фону. Я використовую 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 <4.3, що використовує, setCrossFadeEnabled(true)викликає небажаний ефект білого відтінку, тому мені довелося переключитися на суцільний колір <<4.3, використовуючи метод @Roman Minenok ValueAnimator, зазначений вище.


Це саме те, що я шукав. Дякую! :)
cyph3r

7

Відповідь дається багатьма способами. Ви можете також використовувати 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();

7

Документація щодо анімації, що працює на 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.


Ти врятував мені день. Дякую.
Федеріко Хайланд

1
Відмінна відповідь. Зверніть увагу, що вам може знадобитися android:enterFadeDurationтакож; мій досвід полягав у тому, що без цього моя анімація не працювала вдруге.
Рядок

7

Ось приємна функція, яка дозволяє це:

public static void animateBetweenColors(final @NonNull View viewToAnimateItsBackground, final int colorFrom,
                                        final int colorTo, final int durationInMs) {
    final ColorDrawable colorDrawable = new ColorDrawable(durationInMs > 0 ? colorFrom : colorTo);
    ViewCompat.setBackground(viewToAnimateItsBackground, colorDrawable);
    if (durationInMs > 0) {
        final ValueAnimator colorAnimation = ValueAnimator.ofObject(new ArgbEvaluator(), colorFrom, colorTo);
        colorAnimation.addUpdateListener(animator -> {
            colorDrawable.setColor((Integer) animator.getAnimatedValue());
            ViewCompat.setBackground(viewToAnimateItsBackground, colorDrawable);
        });
        colorAnimation.setDuration(durationInMs);
        colorAnimation.start();
    }
}

А в Котліні:

@JvmStatic
fun animateBetweenColors(viewToAnimateItsBackground: View, colorFrom: Int, colorTo: Int, durationInMs: Int) {
    val colorDrawable = ColorDrawable(if (durationInMs > 0) colorFrom else colorTo)
    ViewCompat.setBackground(viewToAnimateItsBackground, colorDrawable)
    if (durationInMs > 0) {
        val colorAnimation = ValueAnimator.ofObject(ArgbEvaluator(), colorFrom, colorTo)
        colorAnimation.addUpdateListener { animator: ValueAnimator ->
            colorDrawable.color = (animator.animatedValue as Int)
            ViewCompat.setBackground(viewToAnimateItsBackground, colorDrawable)
        }
        colorAnimation.duration = durationInMs.toLong()
        colorAnimation.start()
    }
}

це не підтримує телефони нижньої версії
Kartheek s

2
@Kartheeks ви маєте на увазі Android 10 і нижче? якщо так, то ви можете легко використовувати бібліотеку "nineOldAndroids" для її підтримки: nineoldandroids.com . синтаксис майже точно такий же.
андроїд розробник

для нижчої версії colorAnimation.addUpdateListener (новий ValueAnimator.AnimatorUpdateListener () {@Override public void onAnimationUpdate (анімація ValueAnimator) {colorDravable.setColor ((Integer) animation.getAnimatedValue ()); ViewCompat.setBackground (ViewCompat }setBackground) ;
Махбубур Рахман Хан

5

додати аніматор папок у папку 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>

Ява-файл всередині активності, зателефонуйте до цього

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

3

Використовуйте нижче функцію для Котліна:

private fun animateColorValue(view: View) {
    val colorAnimation =
        ValueAnimator.ofObject(ArgbEvaluator(), Color.GRAY, Color.CYAN)
    colorAnimation.duration = 500L
    colorAnimation.addUpdateListener { animator -> view.setBackgroundColor(animator.animatedValue as Int) }
    colorAnimation.start()
}

Передайте будь-який вид, на який хочете змінити колір.


2

Я виявив, що реалізація використовується 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))));
}

І використовуйте його як завгодно.


0

Виходячи з відповіді ademar111190 , я створив цей метод, і буде імпульсувати колір тла подання між будь-якими двома кольорами:

private void animateBackground(View view, int colorFrom, int colorTo, int duration) {


    ObjectAnimator objectAnimator = ObjectAnimator.ofObject(view, "backgroundColor", new ArgbEvaluator(), colorFrom, colorTo);
    objectAnimator.setDuration(duration);
    //objectAnimator.setRepeatCount(Animation.INFINITE);
    objectAnimator.addListener(new Animator.AnimatorListener() {
        @Override
        public void onAnimationStart(Animator animation) {

        }

        @Override
        public void onAnimationEnd(Animator animation) {
            // Call this method again, but with the two colors switched around.
            animateBackground(view, colorTo, colorFrom, duration);
        }

        @Override
        public void onAnimationCancel(Animator animation) {

        }

        @Override
        public void onAnimationRepeat(Animator animation) {

        }
    });
    objectAnimator.start();
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.