Android'de görünüm arka plan renginin değişimini canlandırın


335

Android'de bir görünümün arka plan rengindeki değişikliği nasıl canlandırıyorsunuz?

Örneğin:

Kırmızı arka plan rengine sahip bir görünüm var. Görünümün arka plan rengi maviye dönüşür. Renkler arasında nasıl yumuşak bir geçiş yapabilirim?

Bu görüşlerle yapılamazsa, bir alternatif kabul edilecektir.


11
Android gibi bir platform için renkler arasında düzgün bir geçişin sorun olmaması beklenebilir. Belki de bunun için görüşler oluşturulmamıştır. Soru hala duruyor.
hpique

Yanıtlar:


374

Ben bu sorun için (oldukça iyi) bir çözüm bulmak sona erdi!

Bunu yapmak için bir TransitionDrawable kullanabilirsiniz . Örneğin, çekilebilir klasördeki bir XML dosyasına şöyle bir şey yazabilirsiniz:

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

Daha sonra, gerçek Görünüm için XML'inizde bu TransitionDrawable'a android:backgroundöznitelikte başvurursunuz.

Bu noktada komut üzerinde kodunuzdaki geçişi yaparak şunları başlatabilirsiniz:

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

Veya şu komutu arayarak geçişi tersine çalıştırın:

transition.reverseTransition(transitionTime);

Bu cevabın ilk olarak gönderildiği sırada mevcut olmayan Property Animation API'sini kullanan başka bir çözüm için Roman'ın cevabına bakın .


3
Teşekkürler mxrider! Bu soruya cevap veriyor. Ne yazık ki benim için işe yaramıyor çünkü TransitionDrawable'ı arka plan olarak gösteren görünüm de animasyonlu olmalı ve görünüm animasyonu arka plan geçişini geçersiz kılıyor gibi görünüyor. Herhangi bir fikir?
hpique 09

6
Animasyonu başlattıktan SONRA TransitionDrawable başlatarak çözüldü.
hpique

2
Müthiş! Çalıştığına sevindim! Android ile xml'de yapabileceğiniz birçok harika şey var - bunların çoğu dokümanlara gömülü ve bence belli değil.
putlaştırmak

4
Hiç belli değil. Renk dinamik olduğu için benim durumumda xml kullanmadığımı belirtmeliyim. Çözümünüz, TransitionDrawable koduna göre oluşturursanız da çalışır.
hpique

2
Ana dezavantajlardan biri, animasyon tam dinleyicinin olmamasıdır
Leo Droidcoder

511

Renkli animasyon için yeni Özellik Animasyonu API'sini kullanabilirsiniz :

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 ile geriye dönük uyumluluk için Jake Wharton'dan Nine Old Androids kütüphanesini kullanın .

getColorYöntem iki seçeneğiniz var bu yüzden Android M kullanımdan kaldırıldı:

  • Destek kitaplığını kullanırsanız, getColoraramaları şu şekilde değiştirmeniz gerekir :

    ContextCompat.getColor(this, R.color.red);
  • destek kitaplığını kullanmazsanız, getColorçağrıları şu şekilde değiştirmeniz gerekir :

    getColor(R.color.red);

2
Property Animation API'sini (veya NineOldAndroid) kullanıyorsanız "musthave" çözümü. Çok düzgün bir şekilde canlandırır.
Dmitry Zaytsev

1
Geçiş süresini bu şekilde ayarlamanın bir yolu var mı?
iGio90

159
@ iGio90 evet, buna inanmayacaksınız ama yöntem setDuration () :) olarak adlandırılıyor
Roman Minenok

6
ValueAnimator.ofArgb(colorFrom, colorTo)konuya daha çok benziyor, ama ne yazık ki yeni.
TWiStErRob

1
Güzel bir çözüm! Teşekkür ederim.
Steve Folly

137

Görünümünüzün arka plan rengini ve hedef renginizi nasıl aldığınıza bağlı olarak bunu yapmanın birkaç farklı yolu vardır.

İlk ikisi Android Mülkiyet Animasyonunu kullanıyor çerçevesini kullanıyor.

Aşağıdaki durumlarda bir Nesne Animatörü kullanın:

  • Görünümünüzün arka plan rengi bir argb xml dosyasındaki değer .
  • Görünümünüz daha önce rengini view.setBackgroundColor()
  • Görünümünüzün arka plan rengi , kontur veya köşe yarıçapları gibi ekstra özellikleri TANIMLAMAYAN bir çekmecede tanımlanmıştır .
  • Görünümünüzün arka plan rengi çekilebilir olarak tanımlanmıştır ve kontur veya köşe yarıçapları gibi ekstra özellikleri kaldırmak istiyorsanız, ekstra özelliklerin kaldırılmasının animasyonlu olmayacağını unutmayın.

Nesne animatörü , nadiren olduğu view.setBackgroundColorbir a örneği olmadıkça, tanımlanabilir çekilebilir olanın yerini alan çağrıyı yaparak çalışır ColorDrawable. Bu, çizilebilir kontur veya köşeler gibi ekstra arka plan özelliklerinin kaldırılacağı anlamına gelir.

Aşağıdaki durumlarda bir Değer Animatörü kullanın:

  • Görünümünüzün arka plan rengi, kontur veya köşe yarıçapları gibi özellikleri de ayarlayan bir çekmecede tanımlanmış ve bunu çalışırken kararlaştırılan yeni bir renge değiştirmek istiyorsunuz.

Aşağıdaki durumlarda çizilebilir bir Geçiş kullanın :

  • Görünümünüz, dağıtımdan önce tanımlanmış iki çekilebilir cihaz arasında geçiş yapmalıdır.

Çözemediğim bir DrawerLayout'u açarken çalışan Geçiş çekmeceleri ile ilgili bazı performans sorunları yaşadım, bu yüzden beklenmedik kekemeyle karşılaşırsanız, benimle aynı hataya rastlamış olabilirsiniz.

Çizilebilir bir StateLists veya bir LayerLists drawable kullanmak istiyorsanız Value Animator örneğini değiştirmeniz gerekir , aksi takdirde final GradientDrawable background = (GradientDrawable) view.getBackground();satırda kilitlenir .

Nesne Animatörü :

Tanımı görüntüle:

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

Bunun ObjectAnimatorgibi bir oluşturun ve kullanın .

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

Ayrıca XMight'ın Android nesnesinde yaptığı gibi bir AnimatorInflater kullanarak animasyon tanımını bir xml'den yükleyebilirsinizAnimator animate background

Değer Animatörü :

Tanımı görüntüle:

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

Çekilebilir tanım:

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

Bunun gibi bir ValueAnimator oluşturun ve kullanın:

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

Geçiş çekilebilir :

Tanımı görüntüle:

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

Çekilebilir tanım:

<?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'ı şu şekilde kullanın:

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

.reverse()Animasyon örneğini çağırarak animasyonları tersine çevirebilirsiniz .

Animasyon yapmanın başka yolları da var, ancak bu üçü muhtemelen en yaygın olanı. Genellikle bir ValueAnimator kullanıyorum.


aslında TransitionDrawable kodunu tanımlamak ve kullanmak mümkündür, ancak bazı nedenlerden dolayı ikinci kez çalışmaz. tuhaf.
android geliştirici

Görünümümde ColorDrawable ayarlanmış olsa bile nesne animatörünü kullanabiliyorum. Ben sadece yerel bir değişkene kaydedin, null olarak ayarlayın ve animasyon bittiğinde, orijinal ColorDrawable geri ayarlayın.
Miloš Černilovský

55

Bir nesne animatörü yapabilirsiniz. Örneğin, bir targetView var ve arka plan rengini değiştirmek istiyorum:

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'den kullanabilirsiniz ofArgb(targetView, "backgroundColor", colorFrom, colorTo). Uygulaması sadece ofInt(...).setEvaluator(new ArgbEvaluator()).
ypresto

20

Bunun gibi renkli animasyonlar istiyorsanız,

Resim açıklamasını buraya girin

bu kod size yardımcı olacaktır:

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
Anim değişkeni başlatıldığı kısım nerede ?
VoW

@VoW, bu sadece ValueAnimator örneğidir.
RBK

anim.setRepeatCount(ValueAnimator.INFINITE);Animasyon olmamalı.Şimdilik aynı, ancak garantimiz yok
MikhailKrishtop

@MikhailKrishtop Animation.INFINITE ile ilgili sorun nedir? developer.android.com/reference/android/view/animation/…
RBK

14

En iyi yol ValueAnimator veColorUtils.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

Bunu başarmanın bir başka kolay yolu AlphaAnimation kullanarak bir solma yapmaktır.

  1. Görünümünüzü bir ViewGroup yapın
  2. 0 dizine match_parent düzen boyutları ile bir alt görünüm ekleyin
  3. Çocuğunuza kapla aynı arka planı verin
  4. Kabın arka planını hedef renge değiştir
  5. AlphaAnimation kullanarak çocuğu karartın.
  6. Animasyon tamamlandığında çocuğu kaldırın (AnimationListener kullanarak)

9

Temel Etkinlikte arka planı değiştirmek için kullandığım yöntem budur. Kodda oluşturulan GradientDrawables kullanıyorum, ancak uygun uyarlanabilir.

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

Güncelleme: Herkesin aynı sorunla karşılaşması durumunda, Android <4.3'te bazı nedenlerden dolayı setCrossFadeEnabled(true)istenmeyen bir beyazlama efekti neden olur, bu nedenle yukarıda belirtilen @Roman Minenok ValueAnimator yöntemini kullanarak <4.3 için düz bir renge geçmek zorunda kaldım.


Tam da aradığım şey buydu. Teşekkürler! :)
cyph3r

7

Cevap birçok şekilde verilir. Ayrıca kullanabilirsiniz ofArgb(startColor,endColor)arasında ValueAnimator.

API> 21 için:

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 destekli animasyonlarla ilgili belgeler korkunç. Sen kullanabilirsiniz: Sadece basıldığında ... üzücü şey animasyon tek özellik uzakta olmasıdır bir düğmeye arka plan rengini animasyonlu saat civarında aradık exitFadeDurationiçinde 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>

Sonra sadece backgroundgörünümünüz için kullanın . Java / Kotlin kodu gerekmez.


Günümü kurtardın. Teşekkürler.
Federico Heiland

1
Mükemmel cevap. Ayrıca ihtiyacınız olabileceğini unutmayın android:enterFadeDuration; deneyimlerim, onsuz, animasyonumun ikinci kez çalışmadığıydı.
String

7

İşte buna izin veren güzel bir fonksiyon:

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

Ve Kotlin'de:

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

bu alt uç sürüm telefonları desteklemez
Kartheek s

2
@Kartheeks demek Android 10 ve önceki sürümleri? öyleyse, bunu desteklemek için kolayca bir "nineOldAndroids" kütüphanesi kullanabilirsiniz: nineoldandroids.com . sözdizimi neredeyse tamamen aynıdır.
android geliştirici

daha düşük sürüm için colorAnimation.addUpdateListener (yeni ValueAnimator.AnimatorUpdateListener () {@AnimationUpdate (ValueAnimator animasyonu) {viewDpatable.setColor ((Integer) animation.getAnimatedValue ()); ViewCompat.setBackground (viewToimateIback); ;
Mahbubur Rahman Khan

5

Bir klasör eklemek animatör içine res klasöründe. (ad animatör olmalıdır ). Bir animatör kaynak dosyası ekleyin. Örneğin 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>

Inside Activity java dosyası, bunu arayın

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

3

Kotlin için aşağıdaki işlevi kullanın:

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

Rengi değiştirmek istediğiniz görünümü iletin.


2

Uygulamanın ArgbEvaluatorAndroid kaynak kodunda renkleri değiştirmede en iyi işi . HSV kullanırken, iki renge bağlı olarak, geçiş benim için çok fazla renk tonundan geçiyordu. Ama bu yöntem böyle değil.

Sadece canlandırılır çalışıyorsanız, kullanım ArgbEvaluatorile ValueAnimatorönerildiği şekilde burada :

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

Ancak, benim gibi iseniz ve geçişinizi bir kullanıcı hareketinden veya bir girdiden geçen başka bir değerle bağlamak istiyorsanız ValueAnimator, çok fazla yardımcı olmaz (API 22 ve üstü için hedeflemiyorsanız, bu durumda ValueAnimator.setCurrentFraction()yöntemi kullanabilirsiniz ). API 22'nin altında hedefleme yaparken, ArgbEvaluatorkaynak kodunda bulunan kodu aşağıda gösterildiği gibi kendi yönteminize ekleyin:

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

Ve dilediğiniz gibi kullanın.


0

Ademar111190'ın cevabına dayanarak, herhangi bir iki renk arasında bir görünümün arka plan rengini darbe verecek bu yöntemi oluşturdum:

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();
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.