Mülk Animasyonuna Genel Bakış

Oluşturma yöntemini deneyin
Jetpack Compose, Android için önerilen kullanıcı arayüzü araç setidir. Oluşturma'da Animasyonların nasıl kullanılacağını öğrenin.

Mülk animasyon sistemi, neredeyse her şeyi canlandırmanıza olanak tanıyan sağlam bir çerçevedir. Ekrana çekilip çekilmemesinden bağımsız olarak, zaman içinde herhangi bir nesne özelliğini değiştirecek bir animasyon tanımlayabilirsiniz. Mülk animasyonu, bir özelliğin (nesnedeki alan) değerini belirli bir süre boyunca değiştirir. Bir şeyi canlandırmak için, canlandırmak istediğiniz nesne özelliğini (ör. bir nesnenin ekrandaki konumu, ne kadar süreyle canlandırmak istediğiniz ve arasında animasyon oluşturmak istediğiniz değerler) belirtirsiniz.

Mülk animasyonu sistemi, bir animasyonun aşağıdaki özelliklerini tanımlayabilmenizi sağlar:

  • Süre: Animasyonun süresini belirtebilirsiniz. Varsayılan uzunluk 300 ms'dir.
  • Zaman interpolasyonu: Özellik değerlerinin, animasyonun geçen süresinin bir fonksiyonu olarak nasıl hesaplanacağını belirtebilirsiniz.
  • Tekrar sayısı ve davranışı: Bir animasyonun belirli bir sürenin sonuna geldiğinde tekrarlanıp tekrarlanmayacağını ve animasyonun kaç kez tekrarlanacağını belirtebilirsiniz. Animasyonun tersten oynatılmasını isteyip istemediğinizi de belirtebilirsiniz. Ters hıza ayarlanırsa, tekrar sayısına ulaşılana kadar animasyonu tekrar tekrar ileri, ardından geriye doğru oynatır.
  • Animatör grupları: Animasyonları, birlikte, sırayla veya belirtilen gecikmelerden sonra oynatılan mantıksal kümeler halinde gruplandırabilirsiniz.
  • Kare yenileme gecikmesi: Animasyonunuzun karelerinin ne sıklıkta yenileneceğini belirleyebilirsiniz. Varsayılan ayar her 10 ms'de bir yenilenecek şekilde ayarlanmıştır. Ancak uygulamanızın kareleri yenileme hızı, sistemin genel olarak ne kadar meşgul olduğuna ve sistemin temel zamanlayıcıyı ne kadar hızlı çalıştırabildiğine bağlıdır.

Tesis animasyonunun tam bir örneğini görmek için GitHub'daki CustomTransition örneğinde yer alan ChangeColor sınıfına bakın.

Tesis animasyonu nasıl çalışır?

İlk olarak, bir animasyonun nasıl çalıştığını basit bir örnekle inceleyelim. Şekil 1'de, ekranda yatay konumunu temsil eden x özelliğiyle canlandırılan varsayımsal bir nesne gösterilmektedir. Animasyonun süresi 40 ms'ye ve hareket mesafesi 40 piksele ayarlanmıştır. Varsayılan kare yenileme hızı olan 10 ms'de bir nesne yatay olarak 10 piksel hareket eder. 40 ms.nin sonunda, animasyon durur ve nesne 40 yatay konumda sona erer. Bu, nesnenin sabit bir hızda hareket ettiği anlamına gelen doğrusal interpolasyon içeren bir animasyon örneğidir.

Şekil 1. Doğrusal animasyon örneği

Ayrıca, doğrusal olmayan bir interpolasyona sahip animasyonlar da belirtebilirsiniz. Şekil 2'de, animasyonun başında hızlanan ve animasyonun sonunda yavaşlayan varsayımsal bir nesne gösterilmektedir. Nesne, 40 ms'de doğrusal olmayan bir şekilde 40 piksel hareket etmeye devam eder. Bu animasyon başlangıçta yarı noktaya kadar hızlandırılır, ardından yarıdan sonuna kadar yavaşlar. Şekil 2'de gösterildiği gibi animasyonun başında ve sonunda kat edilen mesafe, ortasından daha azdır.

2. Şekil. Doğrusal olmayan animasyon örneği

Mülk animasyon sisteminin önemli bileşenlerinin, yukarıda gösterilenlere benzer animasyonları nasıl hesapladığına ayrıntılı bir şekilde göz atalım. Şekil 3'te ana sınıfların birbirleriyle nasıl çalıştığı gösterilmiştir.

3. Şekil. Animasyonlar nasıl hesaplanır?

ValueAnimator nesnesi, animasyonunuzun zamanlamasını (ör. animasyonun ne kadar süredir çalıştığı ve canlandırdığı özelliğin geçerli değeri) izler.

ValueAnimator, animasyon interpolasyonunu tanımlayan bir TimeInterpolator ve canlandırılan özelliğin değerlerinin nasıl hesaplanacağını tanımlayan bir TypeEvaluator içerir. Örneğin, Şekil 2'de TimeInterpolator değeri AccelerateDecelerateInterpolator, TypeEvaluator ise IntEvaluator olur.

Bir animasyon başlatmak için ValueAnimator oluşturun ve buna, canlandırmak istediğiniz özelliğin başlangıç ve bitiş değerleriyle birlikte animasyonun süresini verin. start() yöntemini çağırdığınızda animasyon başlar. Animasyonun tamamı boyunca ValueAnimator, animasyonun süresine ve geçen süreye göre 0 ile 1 arasında bir geçen kesir hesaplar. Geçen oran, animasyonun tamamlandığı sürenin yüzdesini temsil eder. 0 %0, 1 ise %100 anlamına gelir. Örneğin, Şekil 1'de toplam süre t = 40 ms olduğundan t = 10 ms'de geçen kesir 0, 25 olur.

ValueAnimator, geçen kesiri hesaplamayı bitirdiğinde, interpolasyona tabi kesir hesaplamak için halihazırda ayarlı olan TimeInterpolator değerini çağırır. İnterpolasyonlu kesir, geçen kesiri, ayarlanan zaman interpolasyonunu dikkate alan yeni bir kesirle eşler. Örneğin, Şekil 2'de animasyon yavaşça hızlandırıldığı için yaklaşık 0,15 interpole edilen kesir, geçen kesirden (t = 10 ms) göre daha azdır (t = 10 ms). Şekil 1'de interpolasyona tabi kesir her zaman geçen kesirle aynıdır.

İnterpole edilen kesir hesaplandığında ValueAnimator; interpole edilen kesir, başlangıç değeri ve animasyonun bitiş değerine göre animasyon uyguladığınız özelliğin değerini hesaplamak için uygun TypeEvaluator yöntemini çağırır. Örneğin, Şekil 2'de t = 10 ms'de interpolasyonlu kesir 0,15'tir. Dolayısıyla özelliğin o andaki değeri 0,15 × (40 - 0) veya 6 olur.

Mülk animasyonu ile görüntüleme animasyonu arasındaki farklar nelerdir?

Görüntüleme animasyonu sistemi, yalnızca View nesneleri canlandırma olanağı sağlar. Bu nedenle, View olmayan nesnelere animasyon eklemek isterseniz bunu yapmak için kendi kodunuzu uygulamanız gerekir. Görünüm animasyonu sistemi, animasyon uygulamak üzere bir View nesnesinin yalnızca bazı özelliklerini (örneğin, bir Görünümün ölçeklenmesi ve döndürülmesi gibi) (arka plan rengi değil) göstermesi nedeniyle kısıtlanır.

Görüntüleme animasyonu sisteminin bir başka dezavantajı, Görünüm'ün kendisinin değil, yalnızca Görünümün çizildiği yerde değiştirilmesidir. Örneğin, ekranda hareket etmesi için bir düğmeyi canlandırdıysanız düğme doğru çiziliyor ancak düğmeyi tıklayabileceğiniz asıl konum değişmiyor. Bu işlemi gerçekleştirmek için kendi mantığınızı uygulamanız gerekir.

Mülk animasyonu sistemiyle bu kısıtlamalar tamamen kaldırılır ve herhangi bir nesnenin (Görünüm ve Görünüm olmayan öğeler) herhangi bir özelliğini canlandırabilirsiniz. Bu şekilde nesnenin kendisi değiştirilir. Tesis animasyon sistemi, animasyonu yürütme yönteminde de daha sağlamdır. En üst düzeyde, canlandırmak istediğiniz özelliklere (ör. renk, konum veya boyut) animasyonlar atar ve animasyonun interpolasyon ve birden fazla animatörün senkronizasyonu gibi özelliklerini tanımlayabilirsiniz.

Bununla birlikte, görüntüleme animasyonu sisteminin kurulumu daha az zaman alır ve yazmak için daha az kod gerektirir. Animasyon görüntüleme, yapmanız gereken her şeyi yapıyorsa veya mevcut kodunuz zaten istediğiniz şekilde çalışıyorsa özellik animasyon sistemini kullanmanıza gerek yoktur. Kullanım alanı ortaya çıkarsa farklı durumlarda her iki animasyon sistemini de kullanmak mantıklı olabilir.

API'ye genel bakış

Tesis animasyon sistemi API'lerinin çoğunu android.animation içinde bulabilirsiniz. Görüntüleme animasyonu sistemi android.view.animation bölgesinde zaten birçok interpolatör tanımladığından, bu interpolatörleri mülk animasyon sisteminde de kullanabilirsiniz. Aşağıdaki tablolarda, tesis animasyon sisteminin ana bileşenleri açıklanmaktadır.

Animator sınıfı, animasyon oluşturmak için temel yapıyı sağlar. Bu sınıfı yalnızca animasyon değerlerini tam olarak destekleyecek şekilde genişletilmesi gereken minimum düzeyde işlev sunduğundan, normalde bu sınıfı doğrudan kullanmazsınız. Aşağıdaki alt sınıflar Animator kapsamını genişletir:

Tablo 1. Animatörler

Sınıf Açıklama
ValueAnimator Animasyon uygulanacak özelliğin değerlerini de hesaplayan, mülk animasyonu için ana zamanlama motoru. Animasyon değerlerini hesaplayan tüm temel işlevlere sahiptir ve her animasyonun zamanlama ayrıntılarını, bir animasyonun tekrarlanıp tekrarlanmadığı hakkındaki bilgileri, güncelleme etkinliklerini alan işleyicileri ve değerlendirilecek özel türler ayarlama özelliğini içerir. Mülkleri canlandırmak için iki parça vardır: animasyonlu değerleri hesaplama ve bu değerleri canlandırılan nesnede ve mülkte ayarlama. ValueAnimator ikinci parçayı yürütmez. Bu nedenle, ValueAnimator tarafından hesaplanan değerlerde yapılan güncellemeleri dinlemeniz ve kendi mantığınızla canlandırmak istediğiniz nesneleri değiştirmeniz gerekir. Daha fazla bilgi için ValueAnimator ile Animasyon Oluşturma bölümüne bakın.
ObjectAnimator Canlandırılacak bir hedef nesne ve nesne özelliği ayarlamanıza olanak tanıyan bir ValueAnimator alt sınıfı. Bu sınıf, animasyon için yeni bir değer hesaplarken özelliği buna uygun şekilde günceller. Hedef nesnelerde değerlere animasyon ekleme işlemini çok daha kolay hale getirdiği için çoğu zaman ObjectAnimator kullanmayı tercih edersiniz. Ancak ObjectAnimator hedef nesnede belirli erişimci yöntemlerinin bulunmasını zorunlu kılmak gibi birkaç kısıtlama daha olduğu için bazen ValueAnimator öğesini doğrudan kullanmak istersiniz.
AnimatorSet Animasyonları gruplandırıp birbirleriyle ilişkili olarak çalışacak şekilde gruplandıran bir mekanizma sağlar. Animasyonları, sırayla veya belirtilen bir gecikmeden sonra oynatılacak şekilde ayarlayabilirsiniz. Daha fazla bilgi için Animasyon Gruplarıyla birden fazla animasyonun koreografisini oluşturma bölümüne bakın.

Değerlendiriciler, özellik animasyon sistemine belirli bir özelliğin değerlerinin nasıl hesaplanacağını bildirir. Bu parametreler, bir Animator sınıfı tarafından sağlanan zamanlama verilerini, animasyonun başlangıç ve bitiş değerlerini alıp bu verilere dayanarak özelliğin animasyonlu değerlerini hesaplar. Tesis animasyonu sistemi aşağıdaki değerlendiricileri sağlar:

Tablo 2. Değerlendiriciler

Sınıf/Arayüz Açıklama
IntEvaluator int mülklerinin değerlerini hesaplayan varsayılan değerlendirici.
FloatEvaluator float mülklerinin değerlerini hesaplayan varsayılan değerlendirici.
ArgbEvaluator Onaltılık değerler olarak temsil edilen renk özelliklerinin değerlerini hesaplayacak varsayılan değerlendirici.
TypeEvaluator Kendi değerlendiricinizi oluşturmanıza olanak tanıyan bir arayüz. int, float veya renk olmayan bir nesne özelliğini canlandırıyorsanız nesne özelliğinin animasyonlu değerlerinin nasıl hesaplanacağını belirtmek için TypeEvaluator arayüzünü uygulamanız gerekir. Bu türleri varsayılan davranıştan farklı şekilde işlemek istiyorsanız int, float ve renk değerleri için de özel bir TypeEvaluator belirtebilirsiniz. Özel değerlendirici yazma hakkında daha fazla bilgi için TypeEvaluator Kullanma bölümüne bakın.

Zaman interpolatörü, bir animasyondaki belirli değerlerin zamanın bir fonksiyonu olarak nasıl hesaplandığını tanımlar. Örneğin, animasyonların tüm animasyon boyunca doğrusal olarak gerçekleşeceğini belirtebilirsiniz. Diğer bir deyişle, animasyon tüm zaman boyunca eşit şekilde hareket eder. Örneğin, animasyonların başında hızlanan ve sonunda yavaşlayan doğrusal olmayan bir zaman kullanacak şekilde de belirtebilirsiniz. Tablo 3'te, android.view.animation içindeki interpolatörler açıklanmaktadır. Sağlanan interpolatörlerin hiçbiri ihtiyaçlarınıza uymuyorsa TimeInterpolator arayüzünü uygulayın ve kendi arayüzünüzü oluşturun. Özel interpolatör yazma hakkında daha fazla bilgi için İnterpolatörleri kullanma bölümüne bakın.

Tablo 3. İnterpolatörler

Sınıf/Arayüz Açıklama
AccelerateDecelerateInterpolator Değişim oranı yavaş başlayıp biten ancak ortalara doğru hızlanan bir interpolatör.
AccelerateInterpolator Değişim oranı yavaş yavaş başlayıp daha sonra hızlanan bir interpolatördür.
AnticipateInterpolator Değişikliği geriye doğru başlayıp ileri doğru kayan bir interpolatör.
AnticipateOvershootInterpolator Değişikliği geriye doğru başlayıp ileri doğru hızla ilerleyip hedef değeri aşan ve son olarak son değere geri dönen bir interpolatör.
BounceInterpolator Değişikliği en sonda geri dönen bir interpolatör.
CycleInterpolator Animasyonu belirli sayıda döngü boyunca tekrarlanan bir interpolatör.
DecelerateInterpolator Değişim oranı hızlı bir şekilde başlayıp yavaşlayan bir interpolatör.
LinearInterpolator Değişim oranı sabit olan bir interpolatör.
OvershootInterpolator Değişikliği ileri gidip son değeri aşan ve ardından geri gelen bir interpolatör.
TimeInterpolator Kendi interpolatörünüzü uygulamanıza olanak tanıyan arayüz.

ValueAnimator kullanarak animasyon uygulama

ValueAnimator sınıfı, animasyon uygulamak için bir int, float veya renk değeri grubu belirterek animasyon süresi boyunca belirli bir türdeki değerleri canlandırmanıza olanak tanır. Fabrika yöntemlerinden birini çağırarak bir ValueAnimator edinirsiniz: ofInt(), ofFloat() veya ofObject(). Örnek:

Kotlin

ValueAnimator.ofFloat(0f, 100f).apply {
    duration = 1000
    start()
}

Java

ValueAnimator animation = ValueAnimator.ofFloat(0f, 100f);
animation.setDuration(1000);
animation.start();

Bu kodda start() yöntemi çalıştırıldığında ValueAnimator, 1.000 ms'lik bir süre boyunca animasyonun 0 ile 100 arasındaki değerlerini hesaplamaya başlar.

Aşağıdakileri yaparak, animasyon oluşturulacak özel bir tür de belirtebilirsiniz:

Kotlin

ValueAnimator.ofObject(MyTypeEvaluator(), startPropertyValue, endPropertyValue).apply {
    duration = 1000
    start()
}

Java

ValueAnimator animation = ValueAnimator.ofObject(new MyTypeEvaluator(), startPropertyValue, endPropertyValue);
animation.setDuration(1000);
animation.start();

Bu kodda ValueAnimator, start() yöntemi çalışırken MyTypeEvaluator tarafından sağlanan mantığı kullanarak 1.000 ms'lik bir süre boyunca startPropertyValue ile endPropertyValue arasındaki animasyonun değerlerini hesaplamaya başlar.

Animasyonun değerlerini, aşağıdaki kodda gösterildiği gibi ValueAnimator nesnesine bir AnimatorUpdateListener ekleyerek kullanabilirsiniz:

Kotlin

ValueAnimator.ofObject(...).apply {
    ...
    addUpdateListener { updatedAnimation ->
        // You can use the animated value in a property that uses the
        // same type as the animation. In this case, you can use the
        // float value in the translationX property.
        textView.translationX = updatedAnimation.animatedValue as Float
    }
    ...
}

Java

animation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator updatedAnimation) {
        // You can use the animated value in a property that uses the
        // same type as the animation. In this case, you can use the
        // float value in the translationX property.
        float animatedValue = (float)updatedAnimation.getAnimatedValue();
        textView.setTranslationX(animatedValue);
    }
});

onAnimationUpdate() yönteminde, güncellenen animasyon değerine erişebilir ve bunu görünümlerinizden birinin mülkünde kullanabilirsiniz. İşleyiciler hakkında daha fazla bilgi için Animasyon işleyicileri hakkındaki bölüme bakın.

ObjectAnimator kullanarak animasyon oluşturma

ObjectAnimator, ValueAnimator alt sınıfıdır (önceki bölümde açıklanmıştır) ve zamanlama motorunu ve ValueAnimator değer hesaplamasını, hedef nesnenin adlandırılmış özelliğini canlandırma özelliğiyle birleştirir. Animasyonlu özellik otomatik olarak güncellendiğinden artık ValueAnimator.AnimatorUpdateListener öğesini uygulamanız gerekmediğinden bu, herhangi bir nesnenin animasyonunu çok daha kolay hale getirir.

ObjectAnimator örneği oluşturmak ValueAnimator ile benzerdir ancak aynı zamanda nesneyi ve nesnenin özelliğinin adını da (Dize olarak) ve arasında animasyon oluşturulacak değerleri belirtirsiniz:

Kotlin

ObjectAnimator.ofFloat(textView, "translationX", 100f).apply {
    duration = 1000
    start()
}

Java

ObjectAnimator animation = ObjectAnimator.ofFloat(textView, "translationX", 100f);
animation.setDuration(1000);
animation.start();

ObjectAnimator özelliklerinin doğru şekilde güncellenmesi için aşağıdakileri yapmanız gerekir:

  • Canlandırmakta olduğunuz nesne özelliğinin set<PropertyName>() biçiminde bir belirleyici işlevi (deve durumunda) olmalıdır. ObjectAnimator, animasyon sırasında özelliği otomatik olarak güncellediğinden, bu ayarlayıcı yöntemiyle mülke erişebilmesi gerekir. Örneğin, mülk adı foo ise setFoo() yönteminizin olması gerekir. Bu setter yöntemi mevcut değilse üç seçeneğiniz vardır:
    • Gerekli haklara sahipseniz setter yöntemini sınıfa ekleyin.
    • Değiştirme hakkına sahip olduğunuz bir sarmalayıcı sınıfı kullanın ve bu sarmalayıcının değeri geçerli bir setter yöntemiyle alıp orijinal nesneye yönlendirmesini sağlayın.
    • Bunun yerine ValueAnimator politikasını kullanın.
  • ObjectAnimator fabrika yöntemlerinden birinde values... parametresi için yalnızca bir değer belirtirseniz bunun animasyonun bitiş değeri olduğu varsayılır. Dolayısıyla, animasyon uyguladığınız nesne özelliğinin, animasyonun başlangıç değerini elde etmek için kullanılan bir getter işlevine sahip olması gerekir. Getter işlevi get<PropertyName>() biçiminde olmalıdır. Örneğin, mülk adı foo ise getFoo() yönteminizin olması gerekir.
  • Canlandırdığınız mülkün "alıcı (gerekirse)" ve ayarlayıcı yöntemleri, ObjectAnimator için belirlediğiniz başlangıç ve bitiş değerleriyle aynı türde çalışmalıdır. Örneğin, aşağıdaki ObjectAnimator öğesini oluşturursanız targetObject.setPropName(float) ve targetObject.getPropName() öğelerine sahip olmanız gerekir:
    ObjectAnimator.ofFloat(targetObject, "propName", 1f)
    
  • Canlandırdığınız özellik veya nesneye bağlı olarak, ekranı güncellenen animasyonlu değerlerle yeniden çizmeye zorlamak için bir Görünümde invalidate() yöntemini çağırmanız gerekebilir. Bu işlemi onAnimationUpdate() geri çağırmasında yaparsınız. Örneğin, bir Çekilebilir nesnenin renk özelliğine animasyon eklemek, yalnızca nesne kendini yeniden çizdiğinde ekranda güncelleme yapılmasına neden olur. View'daki setAlpha() ve setTranslationX() gibi özellik belirleyicilerin tümü, Görünümü düzgün bir şekilde geçersiz kılar. Bu nedenle, bu yöntemleri yeni değerlerle çağırırken Görünümü geçersiz kılmanız gerekmez. İşleyiciler hakkında daha fazla bilgi için Animasyon işleyicileri hakkındaki bölüme bakın.

AnimatorSet kullanarak birden fazla animasyonun koreografisini oluşturma

Çoğu durumda, başka bir animasyonun ne zaman başladığına veya bittiğine bağlı olan bir animasyonu oynatmak istersiniz. Android sistemi, animasyonları bir AnimatorSet içinde gruplandırmanıza olanak tanır. Böylece animasyonların eş zamanlı olarak mı, sıralı olarak mı yoksa belirli bir gecikmeden sonra mı başlatılacağını belirleyebilirsiniz. Ayrıca AnimatorSet nesneleri birbirinin içine yerleştirebilirsiniz.

Aşağıdaki kod snippet'i, aşağıdaki Animator nesnelerini aşağıdaki şekilde oynatır:

  1. bounceAnim oynatır.
  2. squashAnim1, squashAnim2, stretchAnim1 ve stretchAnim2 aynı anda çalar.
  3. bounceBackAnim oynatır.
  4. fadeAnim oynatır.

Kotlin

val bouncer = AnimatorSet().apply {
    play(bounceAnim).before(squashAnim1)
    play(squashAnim1).with(squashAnim2)
    play(squashAnim1).with(stretchAnim1)
    play(squashAnim1).with(stretchAnim2)
    play(bounceBackAnim).after(stretchAnim2)
}
val fadeAnim = ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f).apply {
    duration = 250
}
AnimatorSet().apply {
    play(bouncer).before(fadeAnim)
    start()
}

Java

AnimatorSet bouncer = new AnimatorSet();
bouncer.play(bounceAnim).before(squashAnim1);
bouncer.play(squashAnim1).with(squashAnim2);
bouncer.play(squashAnim1).with(stretchAnim1);
bouncer.play(squashAnim1).with(stretchAnim2);
bouncer.play(bounceBackAnim).after(stretchAnim2);
ValueAnimator fadeAnim = ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f);
fadeAnim.setDuration(250);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.play(bouncer).before(fadeAnim);
animatorSet.start();

Animasyon dinleyicileri

Aşağıda açıklanan işleyicilerle bir animasyon süresince önemli etkinlikleri dinleyebilirsiniz.

  • Animator.AnimatorListener
  • ValueAnimator.AnimatorUpdateListener
    • onAnimationUpdate(): Animasyonun her karesinde çağrılır. Bir animasyon sırasında ValueAnimator tarafından oluşturulan hesaplanmış değerleri kullanmak için bu etkinliği dinleyin. Değeri kullanmak için etkinliğe geçirilen ValueAnimator nesnesini sorgulayarak getAnimatedValue() yöntemiyle mevcut animasyonlu değeri alın. ValueAnimator kullanıyorsanız bu işleyicinin uygulanması gerekir.

      Canlandırdığınız özellik veya nesneye bağlı olarak, ekranın söz konusu alanını yeni animasyonlu değerlerle yeniden çizmeye zorlamak için bir Görünümde invalidate() çağırmanız gerekebilir. Örneğin, bir Çekilebilir nesnenin renk özelliğine animasyon eklemek, yalnızca nesne kendini yeniden çizdiğinde ekranda güncelleme yapılmasına neden olur. View'daki setAlpha() ve setTranslationX() gibi özellik belirleyicilerin tümü Görünümü düzgün bir şekilde geçersiz kılar. Bu nedenle, bu yöntemleri yeni değerlerle çağırırken Görünümü geçersiz kılmanız gerekmez.

Animator.AnimatorListener arayüzünün tüm yöntemlerini uygulamak istemiyorsanız Animator.AnimatorListener arayüzünü uygulamak yerine AnimatorListenerAdapter sınıfını genişletebilirsiniz. AnimatorListenerAdapter sınıfı, geçersiz kılmayı seçebileceğiniz yöntemlerin boş uygulamalarını sağlar.

Örneğin, aşağıdaki kod snippet'i yalnızca onAnimationEnd() geri çağırması için bir AnimatorListenerAdapter oluşturur:

Kotlin

ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f).apply {
    duration = 250
    addListener(object : AnimatorListenerAdapter() {
        override fun onAnimationEnd(animation: Animator) {
            balls.remove((animation as ObjectAnimator).target)
        }
    })
}

Java

ValueAnimator fadeAnim = ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f);
fadeAnim.setDuration(250);
fadeAnim.addListener(new AnimatorListenerAdapter() {
public void onAnimationEnd(Animator animation) {
    balls.remove(((ObjectAnimator)animation).getTarget());
}

ViewGroup nesnelerinde düzen değişikliklerini canlandırma

Tesis animasyonu sistemi, ViewGroup nesnelerinde yapılan değişiklikleri canlandırma yeteneğinin yanı sıra View nesnelerinin kendilerini canlandırmak için kolay bir yol da sunar.

LayoutTransition sınıfıyla bir ViewGroup içindeki düzen değişikliklerini canlandırabilirsiniz. Bir ViewGroup içindeki görünümler, bir ViewGroup'a eklediğinizde veya kaldırıldığında ya da VISIBLE, INVISIBLE veya GONE ile bir View'un setVisibility() yöntemini çağırdığınızda görünen ve kaybolan bir animasyondan geçebilir. Görünümleri eklediğinizde veya kaldırdığınızda, ViewGroup'taki geri kalan Görünümler, yeni konumlarında hareket edebilir. setAnimator() yöntemini çağırıp bir Animator nesnesini aşağıdaki LayoutTransition sabit değerlerinden biriyle ileterek bir LayoutTransition nesnesinde şu animasyonları tanımlayabilirsiniz:

  • APPEARING: Kapsayıcıda görünen öğelerde çalıştırılan animasyonu belirten bir işaret.
  • CHANGE_APPEARING: Kapsayıcıda yeni bir öğenin görünmesi nedeniyle değişen öğelerde çalıştırılan animasyonu belirten işaret.
  • DISAPPEARING: Kapsayıcıdan kaybolan öğelerde çalıştırılan animasyonu belirten bir işaret.
  • CHANGE_DISAPPEARING: Bir öğenin kapsayıcıdan kaldırılması nedeniyle değişen öğelerde çalıştırılan animasyonu belirten işaret.

Düzen geçişlerinizin görünümünü özelleştirmek için bu dört etkinlik türü için kendi özel animasyonlarınızı tanımlayabilir veya animasyon sistemine varsayılan animasyonları kullanmasını söyleyebilirsiniz.

ViewGroup için android:animateLayoutchanges özelliğini true olarak ayarlamak için aşağıdakileri yapın:

<LinearLayout
    android:orientation="vertical"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:id="@+id/verticalContainer"
    android:animateLayoutChanges="true" />

Bu özelliğin doğru değerine ayarlanması, ViewGroup'a eklenen veya kaldırılan Görünümlerin yanı sıra ViewGroup'taki geri kalan Görünümler için de otomatik olarak animasyon uygular.

StateListAnimator'ı kullanarak görünüm durumu değişikliklerini canlandırma

StateListAnimator sınıfı, bir görünümün durumu değiştiğinde çalışan animatörler tanımlamanızı sağlar. Bu nesne, bir Animator nesnesi için sarmalayıcı görevi görür ve belirtilen görünüm durumu ("basıldı" veya "odaklanmış" gibi) her değiştiğinde bu animasyonu çağırır.

StateListAnimator, her biri StateListAnimator sınıfı tarafından tanımlanan farklı bir görünüm durumu belirten kök <selector> öğesi ve alt <item> öğelerine sahip XML kaynağında tanımlanabilir. Her <item>, bir özellik animasyonu grubunun tanımını içerir.

Örneğin, aşağıdaki dosya basıldığında görünümün x ve y ölçeğini değiştiren bir durum listesi animatörü oluşturur:

res/xml/animate_scale.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- the pressed state; increase x and y size to 150% -->
    <item android:state_pressed="true">
        <set>
            <objectAnimator android:propertyName="scaleX"
                android:duration="@android:integer/config_shortAnimTime"
                android:valueTo="1.5"
                android:valueType="floatType"/>
            <objectAnimator android:propertyName="scaleY"
                android:duration="@android:integer/config_shortAnimTime"
                android:valueTo="1.5"
                android:valueType="floatType"/>
        </set>
    </item>
    <!-- the default, non-pressed state; set x and y size to 100% -->
    <item android:state_pressed="false">
        <set>
            <objectAnimator android:propertyName="scaleX"
                android:duration="@android:integer/config_shortAnimTime"
                android:valueTo="1"
                android:valueType="floatType"/>
            <objectAnimator android:propertyName="scaleY"
                android:duration="@android:integer/config_shortAnimTime"
                android:valueTo="1"
                android:valueType="floatType"/>
        </set>
    </item>
</selector>

Durum listesi animatörünü bir görünüme eklemek için android:stateListAnimator özelliğini aşağıdaki gibi ekleyin:

<Button android:stateListAnimator="@xml/animate_scale"
        ... />

Artık bu düğmenin durumu değiştiğinde animate_scale.xml içinde tanımlanan animasyonlar kullanılmaktadır.

Alternatif olarak, kodunuzdaki bir görünüme durum listesi animatörü atamak için AnimatorInflater.loadStateListAnimator() yöntemini kullanabilir ve View.setStateListAnimator() yöntemiyle görünümünüze animatör atayabilirsiniz.

Görünümün özelliklerine animasyon eklemek yerine, AnimatedStateListDrawable işlevini kullanarak durum değişiklikleri arasında çekilebilir bir animasyon oynatabilirsiniz. Android 5.0'daki sistem widget'larından bazıları varsayılan olarak bu animasyonları kullanır. Aşağıdaki örnekte, AnimatedStateListDrawable kaynağının XML kaynağı olarak nasıl tanımlanacağı gösterilmektedir:

<!-- res/drawable/myanimstatedrawable.xml -->
<animated-selector
    xmlns:android="http://schemas.android.com/apk/res/android">

    <!-- provide a different drawable for each state-->
    <item android:id="@+id/pressed" android:drawable="@drawable/drawableP"
        android:state_pressed="true"/>
    <item android:id="@+id/focused" android:drawable="@drawable/drawableF"
        android:state_focused="true"/>
    <item android:id="@id/default"
        android:drawable="@drawable/drawableD"/>

    <!-- specify a transition -->
    <transition android:fromId="@+id/default" android:toId="@+id/pressed">
        <animation-list>
            <item android:duration="15" android:drawable="@drawable/dt1"/>
            <item android:duration="15" android:drawable="@drawable/dt2"/>
            ...
        </animation-list>
    </transition>
    ...
</animated-selector>

TypeEvaluator kullanma

Android sistemi tarafından bilinmeyen bir türe animasyon eklemek isterseniz TypeEvaluator arayüzünü uygulayarak kendi değerlendiricinizi oluşturabilirsiniz. Android sistemi tarafından bilinen türler, IntEvaluator, FloatEvaluator ve ArgbEvaluator türü değerlendiricileri tarafından desteklenen int, float veya renktir.

TypeEvaluator arayüzünde yalnızca bir yöntem kullanılabilir: evaluate() yöntemi. Bu, kullanmakta olduğunuz animatörün, animasyonun geçerli noktasında animasyonlu mülkünüz için uygun bir değer döndürmesini sağlar. FloatEvaluator sınıfı bunun nasıl yapılacağını gösterir:

Kotlin

private class FloatEvaluator : TypeEvaluator<Any> {

    override fun evaluate(fraction: Float, startValue: Any, endValue: Any): Any {
        return (startValue as Number).toFloat().let { startFloat ->
            startFloat + fraction * ((endValue as Number).toFloat() - startFloat)
        }
    }

}

Java

public class FloatEvaluator implements TypeEvaluator {

    public Object evaluate(float fraction, Object startValue, Object endValue) {
        float startFloat = ((Number) startValue).floatValue();
        return startFloat + fraction * (((Number) endValue).floatValue() - startFloat);
    }
}

Not: ValueAnimator (veya ObjectAnimator) çalıştırıldığında, animasyonun geçerli geçen bölümünü (0 ile 1 arasında bir değer) hesaplar ve ardından, hangi interpolatörü kullandığınıza bağlı olarak bunun interpolasyona tabi bir sürümünü hesaplar. İnterpole edilen kesir, TypeEvaluator öğenizin fraction parametresi aracılığıyla aldığı orandır. Bu nedenle, animasyonlu değerleri hesaplarken interpolatörü dikkate almanız gerekmez.

İnterpolatör kullanın

İnterpolatör, bir animasyondaki belirli değerlerin zaman fonksiyonu olarak nasıl hesaplandığını tanımlar. Örneğin, animasyonların tüm animasyon boyunca doğrusal olarak gerçekleşeceğini belirtebilirsiniz. Diğer bir deyişle, animasyon tüm zaman boyunca eşit şekilde hareket eder. Örneğin, animasyonların başında veya sonunda hızlanma veya yavaşlama kullanarak doğrusal olmayan bir zaman kullanacak şekilde animasyonlar belirtebilirsiniz.

Animasyon sistemindeki interpolatörler, animasyonda geçen süreyi temsil eden Animatörlerden bir kesir alır. İnterpolatörler, bu oranı, sağlamayı amaçladıkları animasyon türüyle uyumlu olacak şekilde değiştirir. Android sistemi, android.view.animation package bölgesinde bir dizi yaygın interpolatör sağlar. Bunların hiçbiri ihtiyaçlarınıza uymuyorsa TimeInterpolator arayüzünü uygulayıp kendi arayüzünüzü oluşturabilirsiniz.

Örnek olarak, varsayılan interpolatör AccelerateDecelerateInterpolator ve LinearInterpolator tarafından interpolasyon uygulanan kesirlerin nasıl hesaplandığı aşağıda gösterilmiştir. LinearInterpolator, geçen oran üzerinde herhangi bir etkisi yoktur. AccelerateDecelerateInterpolator, animasyona doğru hızlanarak yavaşlar. Aşağıdaki yöntemler bu interpolatörlerin mantığını tanımlar:

AccelerateDecelerateInterpolator

Kotlin

override fun getInterpolation(input: Float): Float =
        (Math.cos((input + 1) * Math.PI) / 2.0f).toFloat() + 0.5f

Java

@Override
public float getInterpolation(float input) {
    return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f;
}

Lineer İnterpolatör

Kotlin

override fun getInterpolation(input: Float): Float = input

Java

@Override
public float getInterpolation(float input) {
    return input;
}

Aşağıdaki tabloda, 1.000 ms süren bir animasyon için bu interpolatörler tarafından hesaplanan yaklaşık değerler gösterilmektedir:

geçen ms Geçen kesir/İnterpole edilmiş oran (Doğrusal) İnterpole edilmiş kesir (Hızlandır/yavaşla)
0 0 0
200 0,2 0,1
400 0,4 0,345
600 0,6 0,8
800 0,8 0,9
1.000 1 1

Tabloda gösterildiği gibi LinearInterpolator, değerleri aynı hızda değiştirir (geçen her 200 ms için 0,2). AccelerateDecelerateInterpolator, değerleri LinearInterpolator ile karşılaştırıldığında 200 ms ile 600 ms arasında, daha yavaş ve 600 ms ile 1.000 ms arasında değiştirir.

Animasyon karelerini belirtme

Keyframe nesnesi, bir animasyonun belirli bir zamanındaki belirli bir durumu tanımlamanızı sağlayan bir zaman/değer çiftinden oluşur. Her animasyon karesinin, önceki animasyon karesinin zamanı ile bu animasyon karesinin zamanı arasındaki zaman aralığındaki davranışını kontrol etmek için kendi interpolatörü de olabilir.

Bir Keyframe nesnesini somutlaştırmak için uygun Keyframe türünü elde etmek üzere fabrika yöntemlerinden birini (ofInt(), ofFloat() veya ofObject()) kullanmanız gerekir. Daha sonra, bir PropertyValuesHolder nesnesi almak için ofKeyframe() fabrika yöntemini çağırırsınız. Nesneyi aldığınızda, PropertyValuesHolder nesnesini ve canlandırılacak nesneyi geçirerek bir animatör elde edebilirsiniz. Aşağıdaki kod snippet'inde bunun nasıl yapılacağı gösterilmektedir:

Kotlin

val kf0 = Keyframe.ofFloat(0f, 0f)
val kf1 = Keyframe.ofFloat(.5f, 360f)
val kf2 = Keyframe.ofFloat(1f, 0f)
val pvhRotation = PropertyValuesHolder.ofKeyframe("rotation", kf0, kf1, kf2)
ObjectAnimator.ofPropertyValuesHolder(target, pvhRotation).apply {
    duration = 5000
}

Java

Keyframe kf0 = Keyframe.ofFloat(0f, 0f);
Keyframe kf1 = Keyframe.ofFloat(.5f, 360f);
Keyframe kf2 = Keyframe.ofFloat(1f, 0f);
PropertyValuesHolder pvhRotation = PropertyValuesHolder.ofKeyframe("rotation", kf0, kf1, kf2);
ObjectAnimator rotationAnim = ObjectAnimator.ofPropertyValuesHolder(target, pvhRotation);
rotationAnim.setDuration(5000);

Görüntülemeleri canlandır

Mülk animasyon sistemi, View nesnelerinin basitleştirilmiş animasyonuna olanak tanır ve görünüm animasyon sistemine göre birkaç avantaj sunar. Görüntüleme animasyonu sistemi, çizilme şeklini değiştirerek View nesnelerini dönüştürdü. Görünümün değiştirilebilecek herhangi bir özelliği olmadığı için bu işlem her Görünümün kapsayıcısında gerçekleştirildi. Bu durum, Görünüme animasyon uygulanmasına neden oldu ancak Görünüm nesnesinin kendisinde herhangi bir değişikliğe neden olmadı. Bu durum, bir nesnenin ekranda farklı bir konumda çizilmiş olsa bile hâlâ orijinal konumunda mevcut olması gibi bir davranışa yol açıyordu. Android 3.0'da bu dezavantajı ortadan kaldırmak için yeni özelliklerin yanı sıra karşılık gelen "alıcı ve setter" yöntemleri eklenmiştir.

Mülk animasyon sistemi, Görünüm nesnelerindeki gerçek özellikleri değiştirerek ekrandaki Görünümler'i canlandırabilir. Buna ek olarak, Görünümler, özellikleri her değiştirildiğinde ekranı yenilemek için invalidate() yöntemini de otomatik olarak çağırır. View sınıfında, özellik animasyonlarını kolaylaştıran yeni özellikler şunlardır:

  • translationX ve translationY: Bu özellikler, Görünüm'ün düzen kapsayıcısı tarafından ayarlanan sol ve üst koordinatlarına göre nerede bir delta olarak konumlandırılacağını kontrol eder.
  • rotation, rotationX ve rotationY: Bu özellikler, pivot noktası etrafında döndürmeyi 2D (rotation özelliği) ve 3D olarak kontrol eder.
  • scaleX ve scaleY: Bu özellikler, bir Görünümün pivot noktası çevresinde 2D ölçeklemesini kontrol eder.
  • pivotX ve pivotY: Bu özellikler, etrafında döndürme ve ölçeklendirme dönüşümlerinin gerçekleştiği pivot noktanın konumunu kontrol eder. Pivot noktası, varsayılan olarak nesnenin merkezinde bulunur.
  • x ve y: Bunlar, Görünümün kapsayıcısındaki son konumunu, sol ve üst değerler ile çeviriX ve çeviriY değerlerinin toplamı olarak açıklayan basit yardımcı program özellikleridir.
  • alpha: Görünümde alfa şeffaflığını gösterir. Bu değer varsayılan olarak 1'dir (opak). 0 değeri tam şeffaflığı temsil eder (görünmez).

View nesnesinin rengi veya döndürme değeri gibi bir özelliğini canlandırmak için tek yapmanız gereken bir özellik animatörü oluşturmak ve canlandırmak istediğiniz View özelliğini belirtmektir. Örnek:

Kotlin

ObjectAnimator.ofFloat(myView, "rotation", 0f, 360f)

Java

ObjectAnimator.ofFloat(myView, "rotation", 0f, 360f);

Animatör oluşturma hakkında daha fazla bilgi için ValueAnimator ve ObjectAnimator ile animasyon oluşturma bölümlerine bakın.

ViewPropertyAnimator kullanarak animasyon uygulama

ViewPropertyAnimator, tek bir temel Animator nesnesi kullanarak View öğesinin çeşitli özelliklerini paralel olarak canlandırmak için basit bir yol sağlar. Görünüm özelliklerinin gerçek değerlerini değiştirdiği ancak aynı anda birçok özelliği canlandırdığında daha verimli olduğu için ObjectAnimator işlevine çok benzer davranır. Ayrıca, ViewPropertyAnimator kodu çok daha kısa ve öz ve okuması daha kolay. Aşağıdaki kod snippet'leri, bir görünümün x ve y özelliğini eş zamanlı olarak canlandırırken birden çok ObjectAnimator nesnesi, tek bir ObjectAnimator ve ViewPropertyAnimator öğesinin kullanılması arasındaki farkları göstermektedir.

Birden çok ObjectAnimator nesnesi

Kotlin

val animX = ObjectAnimator.ofFloat(myView, "x", 50f)
val animY = ObjectAnimator.ofFloat(myView, "y", 100f)
AnimatorSet().apply {
    playTogether(animX, animY)
    start()
}

Java

ObjectAnimator animX = ObjectAnimator.ofFloat(myView, "x", 50f);
ObjectAnimator animY = ObjectAnimator.ofFloat(myView, "y", 100f);
AnimatorSet animSetXY = new AnimatorSet();
animSetXY.playTogether(animX, animY);
animSetXY.start();

Bir Nesne Animatörü

Kotlin

val pvhX = PropertyValuesHolder.ofFloat("x", 50f)
val pvhY = PropertyValuesHolder.ofFloat("y", 100f)
ObjectAnimator.ofPropertyValuesHolder(myView, pvhX, pvhY).start()

Java

PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("x", 50f);
PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("y", 100f);
ObjectAnimator.ofPropertyValuesHolder(myView, pvhX, pvhY).start();

ViewPropertyAnimator

Kotlin

myView.animate().x(50f).y(100f)

Java

myView.animate().x(50f).y(100f);

ViewPropertyAnimator hakkında daha ayrıntılı bilgi edinmek için ilgili Android Developers blog yayınına bakın.

Animasyonları XML olarak bildirme

Özellik animasyonu sistemi, özellik animasyonlarını programatik olarak yapmak yerine XML ile bildirmenizi sağlar. Animasyonlarınızı XML'de tanımlayarak, animasyonlarınızı birden fazla etkinlikte kolayca yeniden kullanabilir ve animasyon sırasını daha kolay bir şekilde düzenleyebilirsiniz.

Android 3.1'den itibaren, yeni mülk animasyon API'lerini kullanan animasyon dosyalarını eski animasyon görüntüleme çerçevesini kullananlardan ayırt etmek için mülk animasyonlarına ait XML dosyalarını res/animator/ dizinine kaydetmeniz gerekir.

Aşağıdaki tesis animasyonu sınıflarında, aşağıdaki XML etiketleriyle XML bildirimi desteği bulunur:

XML bildiriminizde kullanabileceğiniz özellikleri bulmak için Animasyon kaynakları bölümüne bakın. Aşağıdaki örnekte iki nesne animasyonu grubu sırayla oynatılır ve iç içe yerleştirilmiş ilk grup iki nesne animasyonunu birlikte oynatır:

<set android:ordering="sequentially">
    <set>
        <objectAnimator
            android:propertyName="x"
            android:duration="500"
            android:valueTo="400"
            android:valueType="intType"/>
        <objectAnimator
            android:propertyName="y"
            android:duration="500"
            android:valueTo="300"
            android:valueType="intType"/>
    </set>
    <objectAnimator
        android:propertyName="alpha"
        android:duration="500"
        android:valueTo="1f"/>
</set>

Bu animasyonu çalıştırmak için kodunuzdaki XML kaynaklarını bir AnimatorSet nesnesine dönüştürmeniz ve daha sonra animasyon grubunu başlatmadan önce tüm animasyonlar için hedef nesneleri ayarlamanız gerekir. setTarget() çağrısı, kolaylık sağlamak amacıyla AnimatorSet öğesinin tüm alt öğeleri için tek bir hedef nesne ayarlar. Aşağıdaki kod bunun nasıl yapılacağını gösterir:

Kotlin

(AnimatorInflater.loadAnimator(myContext, R.animator.property_animator) as AnimatorSet).apply {
    setTarget(myObject)
    start()
}

Java

AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(myContext,
    R.animator.property_animator);
set.setTarget(myObject);
set.start();

Aşağıdaki örnekte gösterildiği gibi XML'de bir ValueAnimator belirtmeniz de mümkündür:

<animator xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="1000"
    android:valueType="floatType"
    android:valueFrom="0f"
    android:valueTo="-100f" />

Kodunuzda önceki ValueAnimator öğesini kullanmak için nesneyi şişirmeniz, bir AnimatorUpdateListener eklemeniz, güncellenmiş animasyon değerini almanız ve bunu aşağıdaki kodda gösterildiği gibi görünümlerinizden birinin özelliğinde kullanmanız gerekir:

Kotlin

(AnimatorInflater.loadAnimator(this, R.animator.animator) as ValueAnimator).apply {
    addUpdateListener { updatedAnimation ->
        textView.translationX = updatedAnimation.animatedValue as Float
    }

    start()
}

Java

ValueAnimator xmlAnimator = (ValueAnimator) AnimatorInflater.loadAnimator(this,
        R.animator.animator);
xmlAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator updatedAnimation) {
        float animatedValue = (float)updatedAnimation.getAnimatedValue();
        textView.setTranslationX(animatedValue);
    }
});

xmlAnimator.start();

Özellik animasyonlarını tanımlamaya yönelik XML söz dizimi hakkında bilgi için Animasyon kaynakları bölümüne bakın.

Kullanıcı arayüzü performansı üzerindeki olası etkiler

Kullanıcı arayüzünü güncelleyen animatörler, animasyonun çalıştırıldığı her kare için ekstra oluşturma çalışmasına neden olur. Bu nedenle, kaynakları yoğun olarak kullanan animasyonlar kullanmak uygulamanızın performansını olumsuz yönde etkileyebilir.

Kullanıcı arayüzünüzü canlandırmak için gereken çalışmalar, oluşturma ardışık düzeninin animasyon aşamasına eklenir. Profil GPU Oluşturma'yı etkinleştirip animasyon sahnesini izleyerek animasyonlarınızın uygulamanızın performansını etkileyip etkilemediğini öğrenebilirsiniz. Daha fazla bilgi için Profil GPU oluşturma adım adım açıklamalı kılavuzu bölümüne bakın.