Ringkasan Animasi Properti

Mencoba cara Compose
Jetpack Compose adalah toolkit UI yang direkomendasikan untuk Android. Pelajari cara menggunakan Animasi di Compose.

Sistem animasi properti adalah framework andal yang memungkinkan Anda menganimasikan hampir semua hal. Anda dapat menentukan animasi untuk mengubah properti objek dari waktu ke waktu, terlepas dari apakah properti objek tersebut digambar ke layar atau tidak. Animasi properti mengubah nilai properti (kolom dalam objek) selama jangka waktu tertentu. Untuk menganimasikan sesuatu, Anda perlu menentukan properti objek yang ingin dianimasikan, seperti posisi objek di layar, berapa lama Anda ingin menganimasikan objek itu, dan nilai yang Anda inginkan untuk menganimasikan antar-objek.

Sistem animasi properti memungkinkan Anda menentukan karakteristik animasi berikut:

  • Durasi: Anda dapat menentukan durasi animasi. Durasi defaultnya adalah 300 milidetik.
  • Interpolasi waktu: Anda dapat menentukan cara menghitung nilai untuk properti sebagai fungsi dari waktu berlalu saat ini untuk animasi tersebut.
  • Jumlah dan perilaku pengulangan: Anda dapat menentukan apakah akan mengulang animasi jika sudah mencapai akhir durasi dan berapa kali animasi akan diulang. Anda juga dapat menentukan apakah Anda ingin animasi diputar secara terbalik atau tidak. Menyetelnya ke mundur akan memutar animasi maju lalu mundur berulang-ulang, hingga mencapai jumlah pengulangan yang ditentukan.
  • Kumpulan animator: Anda dapat mengelompokkan beberapa animasi ke dalam kumpulan logis yang diputar secara bersamaan, berurutan, atau setelah penundaan tertentu.
  • Penundaan refresh frame: Anda dapat menentukan frekuensi refresh frame animasi. Tujuan diatur untuk memperbarui setiap 10 md, tetapi kecepatan pembaruan bingkai aplikasi Anda adalah pada akhirnya tergantung pada seberapa ramai sistem secara keseluruhan dan seberapa cepat sistem dapat melayani {i>timer<i} yang mendasarinya.

Untuk melihat contoh lengkap animasi properti, lihat class ChangeColor dalam contoh CustomTransition di GitHub.

Cara kerja animasi properti

Pertama-tama, mari kita bahas cara kerja animasi melalui sebuah contoh sederhana. Gambar 1 menunjukkan objek hipotetis yang dianimasikan dengan properti x-nya, yang mewakili lokasi horizontal pada layar. Durasi animasi disetel ke 40 md dan jaraknya untuk dilalui adalah 40 {i>pixel<i}. Setiap 10 md, yang merupakan kecepatan refresh frame default, objek bergerak secara horizontal sebesar 10 piksel. Pada akhir 40 md, animasi akan berhenti, dan objek berakhir pada posisi horizontal 40. Ini adalah contoh animasi dengan interpolasi linear, yang berarti objek bergerak dengan kecepatan konstan.

Gambar 1. Contoh animasi linier

Anda juga dapat menentukan animasi untuk memiliki interpolasi non-linear. Gambar 2 mengilustrasikan objek hipotesis yang dipercepat di awal animasi, dan melambat di awal animasi akhir animasi. Objek masih bergerak 40 piksel dalam 40 milidetik, tetapi tidak linier. Di kolom awal, animasi ini dipercepat hingga setengah jalan, lalu melambat dari dari setengah jalan hingga akhir animasi. Seperti yang ditunjukkan Gambar 2, jarak yang ditempuh awal dan akhir animasi lebih kurang dari di tengah.

Gambar 2. Contoh animasi non-linear

Mari kita lihat secara detail bagaimana komponen penting dari sistem animasi properti akan menghitung animasi seperti yang diilustrasikan di atas. Gambar 3 menunjukkan bagaimana class utama bekerja sama satu sama lain.

Gambar 3. Cara animasi dihitung

Objek ValueAnimator melacak pengaturan waktu animasi Anda, seperti berapa lama animasi telah berjalan, dan nilai saat ini dari properti yang dianimasikannya.

ValueAnimator mengenkapsulasi TimeInterpolator, yang menentukan interpolasi animasi, dan TypeEvaluator, yang menentukan cara menghitung nilai untuk properti yang animasi. Misalnya, dalam Gambar 2, TimeInterpolator yang digunakan adalah AccelerateDecelerateInterpolator dan TypeEvaluator akan menjadi IntEvaluator.

Untuk memulai animasi, buat ValueAnimator dan berikan nilai awal dan akhir untuk properti yang ingin Anda animasikan, beserta durasi animasinya. Saat Anda memanggil start(), animasi akan dimulai. Selama seluruh animasi, ValueAnimator menghitung fraksi berlalu antara 0 dan 1, berdasarkan durasi animasi dan berapa banyak waktu yang telah berlalu. Fraksi yang berlalu menunjukkan persentase waktu yang telah diselesaikan animasi, 0 berarti 0% dan 1 berarti 100%. Misalnya, pada Gambar 1, fraksi berlalu pada t = 10 ms akan menjadi 0,25 karena total durasi adalah t = 40 md.

Setelah selesai menghitung fraksi berlalu, ValueAnimator akan memanggil TimeInterpolator yang saat ini ditetapkan, untuk menghitung fraksi terinterpolasi. Fraksi terinterpolasi memetakan fraksi berlalu ke fraksi baru yang memperhitungkan interpolasi waktu yang ditetapkan. Misalnya, dalam Gambar 2, karena animasi bertambah kecepatan secara perlahan, fraksi terinterpolasi lebih kecil (sekitar 0,15) daripada fraksi berlalu (0,25) pada t = 10 mdtk. Dalam Gambar 1, fraksi terinterpolasi selalu sama dengan fraksi berlalu.

Saat fraksi terinterpolasi dihitung, ValueAnimator akan memanggil TypeEvaluator yang sesuai, untuk menghitung nilai properti yang Anda animasikan, berdasarkan fraksi terinterpolasi, nilai awal, dan nilai akhir animasi. Misalnya, dalam Gambar 2, fraksi terinterpolasi adalah 0,15 pada t = 10 mdtk, sehingga nilai properti pada saat itu adalah 0,15 × (40 - 0), atau 6.

Perbedaan antara animasi properti dengan animasi tampilan

Sistem animasi tampilan menyediakan kemampuan untuk hanya menganimasikan objek View, jadi jika Anda ingin menganimasikan objek non-View, Anda harus menerapkan kode Anda sendiri untuk melakukannya. Sistem animasi tampilan juga dibatasi oleh fakta bahwa sistem ini hanya mengekspos beberapa aspek objek View untuk dianimasikan, seperti penskalaan dan rotasi View, tetapi bukan warna latar belakang, misalnya.

Kekurangan lain dari sistem animasi tampilan adalah sistem ini hanya memodifikasi Tampilan digambar, dan bukan Tampilan itu sendiri. Misalnya, jika Anda menganimasikan tombol untuk bergerak di seluruh layar, tombol akan menggambar dengan benar, tetapi lokasi aktual tempat Anda dapat mengklik tombol tidak berubah, sehingga Anda harus menerapkan logika Anda sendiri untuk menangani hal ini.

Dengan sistem animasi properti, batasan ini dihilangkan sepenuhnya, dan Anda dapat menganimasikan properti apa pun dari objek apa pun (View dan non-View) dan objek itu sendiri benar-benar diubah. Sistem animasi properti juga lebih tangguh dalam menangani animasi. Di tingkat tinggi, Anda menetapkan animator ke properti yang ingin dianimasikan, seperti warna, posisi, atau ukuran dan dapat menentukan aspek animasi seperti interpolasi dan sinkronisasi beberapa animator.

Namun, sistem animasi tampilan memerlukan lebih sedikit waktu untuk disiapkan dan lebih sedikit kode untuk ditulis. Jika animasi tampilan bisa menyelesaikan semua hal yang perlu Anda lakukan, atau jika kode yang ada sudah berfungsi sesuai keinginan, Anda tidak perlu menggunakan sistem animasi properti. Hal itu mungkin juga masuk akal untuk menggunakan kedua sistem animasi untuk situasi yang berbeda jika terjadi kasus penggunaan.

Ringkasan API

Anda dapat menemukan sebagian besar API sistem animasi properti di android.animation. Karena sistem animasi tampilan sudah menentukan banyak interpolator di android.view.animation, Anda juga dapat menggunakan interpolator tersebut dalam sistem animasi properti. Tabel berikut menjelaskan elemen utama dari sistem animasi properti.

Class Animator menyediakan struktur dasar untuk membuat animasi. Anda biasanya tidak menggunakan class ini secara langsung karena class ini hanya memberikan sedikit fungsionalitas yang harus diperluas untuk mendukung sepenuhnya nilai animasi. Hal berikut subclass memperluas Animator:

Tabel 1. Animator

Class Deskripsi
ValueAnimator Mesin pengatur waktu utama untuk animasi properti yang juga menghitung nilai untuk properti yang akan dianimasikan. Class ini memiliki semua fungsi inti yang menghitung nilai animasi dan berisi detail pengaturan waktu untuk setiap animasi, informasi tentang apakah animasi berulang atau tidak, pemroses yang menerima peristiwa pembaruan, dan kemampuan untuk menetapkan jenis kustom yang akan dievaluasi. Ada dua bagian dalam properti animasi: menghitung properti animasi nilai dan menetapkan nilai-nilai tersebut pada objek dan properti yang sedang dianimasikan. ValueAnimator tidak melakukan bagian kedua, sehingga Anda harus memantau pembaruan nilai yang dihitung oleh ValueAnimator dan memodifikasi objek yang ingin Anda animasikan dengan logika Anda sendiri. Lihat bagian tentang Membuat animasi dengan ValueAnimator untuk mengetahui informasi selengkapnya.
ObjectAnimator Subclass ValueAnimator yang memungkinkan Anda menetapkan target dan properti objek yang akan dianimasikan. Class ini memperbarui properti yang sesuai saat menghitung nilai baru untuk animasi tersebut. Anda ingin menggunakan ObjectAnimator sepanjang waktu, karena membuat proses animasi nilai pada objek target jauh lebih mudah. Namun, terkadang Anda perlu menggunakan ValueAnimator secara langsung karena ObjectAnimator memiliki beberapa batasan lainnya, seperti mengharuskan metode pengakses tertentu untuk ada di objek target.
AnimatorSet Menyediakan mekanisme untuk mengelompokkan animasi bersama-sama sehingga berjalan di berhubungan satu sama lain. Anda dapat menyetel animasi untuk diputar secara bersamaan, berurutan, atau setelah penundaan yang ditentukan. Lihat bagian Mengatur koreografi beberapa animasi dengan AnimatorSet untuk mengetahui informasi selengkapnya.

Evaluator memberi tahu sistem animasi properti cara menghitung nilai untuk properti tertentu. Metrik ini mengambil data waktu yang disediakan oleh Animator nilai awal dan akhir animasi, serta menghitung nilai animasi properti berdasarkan data ini. Sistem animasi properti menyediakan evaluator berikut:

Tabel 2. Evaluator

Class/Antarmuka Deskripsi
IntEvaluator Evaluator default untuk menghitung nilai properti int.
FloatEvaluator Evaluator default untuk menghitung nilai properti float.
ArgbEvaluator Evaluator default untuk menghitung nilai properti warna yang ditunjukkan sebagai nilai heksadesimal.
TypeEvaluator Antarmuka yang memungkinkan Anda membuat evaluator sendiri. Jika Anda menganimasikan properti objek yang bukan int, float, atau warna, Anda harus menerapkan antarmuka TypeEvaluator untuk menentukan cara menghitung nilai teranimasi properti objek. Anda juga dapat menentukan TypeEvaluator kustom untuk nilai int, float, dan warna, jika Anda ingin memproses jenis tersebut secara berbeda dengan perilaku default. Lihat bagian Menggunakan TypeEvaluator untuk informasi selengkapnya informasi tentang cara menulis penilai khusus (custom evaluator).

Interpolator waktu mendefinisikan bagaimana nilai tertentu dalam sebuah animasi dihitung sebagai fungsi waktu. Misalnya, Anda dapat menentukan animasi agar terjadi secara linear di seluruh animasi, artinya animasi bergerak secara merata sepanjang waktu, atau Anda dapat menentukan animasi menggunakan waktu non-linear, misalnya, berakselerasi di awal dan melambat di akhir animasi. Tabel 3 menjelaskan interpolator yang terdapat dalam android.view.animation. Jika interpolator yang disediakan tidak ada yang sesuai kebutuhan Anda, terapkan antarmuka TimeInterpolator, dan buat antarmuka Anda sendiri. Lihat Menggunakan interpolator untuk mengetahui informasi selengkapnya tentang cara menulis interpolator kustom.

Tabel 3. Interpolator

Class/Antarmuka Deskripsi
AccelerateDecelerateInterpolator Interpolator yang laju perubahannya dimulai dan berakhir dengan lambat, tetapi dipercepat di tengahnya.
AccelerateInterpolator Interpolator yang laju perubahannya dimulai dengan lambat, lalu mereka akan lebih cepat.
AnticipateInterpolator Interpolator yang perubahannya dimulai secara mundur, lalu melejit maju.
AnticipateOvershootInterpolator Interpolator yang perubahannya dimulai secara mundur, melejit maju, dan melampaui nilai target, lalu akhirnya kembali ke nilai akhir.
BounceInterpolator Interpolator yang perubahannya memantul di bagian akhir.
CycleInterpolator Interpolator yang animasinya berulang selama sejumlah siklus tertentu.
DecelerateInterpolator Interpolator yang laju perubahannya dimulai dengan cepat, lalu melambat.
LinearInterpolator Interpolator yang laju perubahannya konstan.
OvershootInterpolator Interpolator yang perubahannya melejit maju dan melampaui nilai terakhir kembali lagi.
TimeInterpolator Antarmuka yang memungkinkan Anda menerapkan interpolator sendiri.

Menganimasikan dengan ValueAnimator

Class ValueAnimator memungkinkan Anda menganimasikan jenis nilai tertentu selama durasi animasi dengan menentukan kumpulan nilai int, float, atau warna yang akan dianimasikan. Anda mendapatkan ValueAnimator dengan memanggil salah satu metode factory-nya: ofInt(), ofFloat(), atau ofObject(). Contoh:

Kotlin

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

Java

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

Dalam kode ini, ValueAnimator mulai menghitung nilai atribut animasi, antara 0 dan 100, selama durasi 1.000 md, saat metode start() berjalan.

Anda juga dapat menentukan jenis kustom yang akan dianimasikan dengan melakukan langkah berikut:

Kotlin

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

Java

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

Dalam kode ini, ValueAnimator mulai menghitung nilai animasi, antara startPropertyValue dan endPropertyValue menggunakan logika yang disediakan oleh MyTypeEvaluator selama 1.000 milidetik, saat metode start() berjalan.

Anda dapat menggunakan nilai animasi tersebut dengan menambahkan sebuah AnimatorUpdateListener ke objek ValueAnimator, seperti yang ditunjukkan dalam kode berikut:

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

Di onAnimationUpdate() Anda dapat mengakses nilai animasi yang diperbarui dan menggunakannya dalam properti salah satu tampilan Anda. Untuk informasi selengkapnya tentang pemroses, lihat bagian tentang Pemroses animasi.

Menganimasikan dengan ObjectAnimator

ObjectAnimator adalah subclass dari ValueAnimator (dibahas di bagian sebelumnya) dan menggabungkan mesin pengaturan waktu dan penghitungan nilai ValueAnimator dengan kemampuan untuk menganimasikan properti bernama dari sebuah objek target. Hal ini mempermudah penganimasian objek apa pun, karena Anda tidak perlu lagi mengimplementasikan ValueAnimator.AnimatorUpdateListener, karena properti yang dianimasikan diperbarui secara otomatis.

Membuat instance ObjectAnimator mirip dengan ValueAnimator, tetapi Anda juga menentukan objek dan nama properti objek tersebut (seperti sebuah String) beserta nilai yang akan dianimasikan antara:

Kotlin

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

Java

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

Agar ObjectAnimator dapat memperbarui properti dengan benar, Anda harus melakukan hal berikut:

  • Properti objek yang Anda animasikan harus memiliki fungsi penyetel (dalam camel case) dengan format set<PropertyName>(). Karena ObjectAnimator secara otomatis memperbarui properti selama animasi, properti harus dapat mengakses properti dengan metode penyetel ini. Misalnya, jika nama properti adalah foo, Anda harus memiliki metode setFoo(). Jika metode penyetel ini tidak ada, Anda memiliki tiga opsi:
    • Menambahkan metode setter ke class jika Anda memiliki hak untuk melakukannya.
    • Gunakan class wrapper yang dapat Anda ubah dan minta agar wrapper menerima nilai dengan metode penyetel yang valid, lalu meneruskannya ke objek aslinya.
    • Sebagai gantinya, gunakan ValueAnimator.
  • Jika Anda hanya menentukan satu nilai untuk parameter values... dalam salah satu metode factory ObjectAnimator, nilai tersebut diasumsikan sebagai nilai akhir animasi. Oleh karena itu, properti objek yang Anda animasikan harus memiliki fungsi pengambil yang digunakan untuk mendapatkan nilai awal animasi. Fungsi pengambil harus dalam format get<PropertyName>(). Misalnya, jika nama properti adalah foo, Anda harus memiliki metode getFoo().
  • Metode pengambil (jika diperlukan) dan penyetel dari properti yang Anda animasikan harus beroperasi pada jenis yang sama dengan nilai awal dan akhir yang Anda tetapkan untuk ObjectAnimator. Misalnya, Anda harus memiliki targetObject.setPropName(float) dan targetObject.getPropName() jika membuat ObjectAnimator berikut:
    ObjectAnimator.ofFloat(targetObject, "propName", 1f)
  • Bergantung pada properti atau objek yang dianimasikan, Anda mungkin perlu memanggil metode invalidate() di View untuk memaksa layar menggambar ulang dirinya sendiri dengan nilai animasi yang diperbarui. Anda melakukannya di callback onAnimationUpdate(). Misalnya, menganimasikan properti warna sebuah objek Drawable hanya akan menyebabkan pembaruan pada ketika objek itu menggambar dirinya sendiri. Semua penyetel properti di View, seperti setAlpha() dan setTranslationX() membatalkan View dengan benar, sehingga Anda tidak perlu membatalkan View saat memanggilnya metode dengan nilai baru. Untuk informasi selengkapnya tentang pemroses, lihat bagian tentang Pemroses animasi.

Mengatur koreografi beberapa animasi dengan AnimatorSet

Dalam banyak kasus, Anda perlu memutar animasi yang bergantung pada kapan animasi lain dimulai atau selesai. Sistem Android memungkinkan Anda menggabungkan beberapa animasi menjadi sebuah AnimatorSet, sehingga Anda dapat menentukan apakah animasi akan mulai diputar secara bersamaan, berurutan, atau setelah penundaan tertentu. Anda juga dapat menempatkan objek AnimatorSet di dalam objek AnimatorSet lainnya.

Cuplikan kode berikut memutar objek Animator berikut dengan cara berikut:

  1. Memutar bounceAnim.
  2. Memutar squashAnim1, squashAnim2, stretchAnim1, dan stretchAnim2 secara bersamaan.
  3. Memutar bounceBackAnim.
  4. Memutar fadeAnim.

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

Pemroses animasi

Anda bisa memproses peristiwa penting selama durasi animasi dengan pemroses yang dijelaskan di bawah ini.

  • Animator.AnimatorListener
  • ValueAnimator.AnimatorUpdateListener
    • onAnimationUpdate() - dipanggil di setiap frame animasi. Proses peristiwa ini untuk menggunakan nilai terhitung yang dihasilkan oleh ValueAnimator selama animasi. Untuk menggunakan nilai, buat kueri objek ValueAnimator diteruskan ke peristiwa untuk mendapatkan nilai animasi saat ini dengan metode getAnimatedValue(). Menerapkan pemroses diperlukan jika Anda menggunakan ValueAnimator.

      Bergantung pada properti atau objek yang dianimasikan, Anda mungkin perlu memanggil invalidate() di View untuk memaksa area layar menggambar ulang dirinya sendiri dengan nilai animasi baru. Misalnya, menganimasikan properti warna sebuah objek Drawable hanya akan menimbulkan pembaruan pada layar jika objek tersebut menggambar ulang dirinya sendiri. Semua penyetel properti di View, seperti setAlpha() dan setTranslationX() membatalkan View dengan benar, jadi Anda tidak perlu membatalkan View saat memanggil metode ini dengan nilai baru.

Anda dapat memperluas class AnimatorListenerAdapter, bukan menerapkan antarmuka Animator.AnimatorListener, jika Anda tidak ingin menerapkan semua metode antarmuka Animator.AnimatorListener. Class AnimatorListenerAdapter menyediakan implementasi kosong dari metode yang dapat Anda pilih untuk diganti.

Misalnya, cuplikan kode berikut membuat AnimatorListenerAdapter hanya untuk callback onAnimationEnd():

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

Menganimasikan perubahan tata letak pada objek ViewGroup

Sistem animasi properti menyediakan kemampuan untuk menganimasikan perubahan pada objek ViewGroup serta menyediakan cara mudah untuk menganimasikan objek View itu sendiri.

Anda dapat menganimasikan perubahan tata letak dalam ViewGroup dengan Class LayoutTransition. Tampilan di dalam ViewGroup dapat Anda akan melihat animasi yang muncul dan menghilang ketika Anda menambahkannya ke atau menghapusnya dari ViewGroup atau saat Anda memanggil permintaan Metode setVisibility() dengan VISIBLE, INVISIBLE, atau GONE. View lainnya di ViewGroup juga dapat mengalami animasi ke posisi barunya saat Anda menambahkan atau menghapus View. Anda dapat menentukan animasi berikut dalam objek LayoutTransition dengan memanggil setAnimator() dan meneruskan objek Animator dengan salah satu konstanta LayoutTransition berikut:

  • APPEARING - Flag yang menunjukkan animasi yang berjalan pada item yang muncul di penampung.
  • CHANGE_APPEARING - Flag yang menunjukkan animasi yang berjalan pada item yang berubah karena ada item baru yang muncul di penampung.
  • DISAPPEARING - Flag yang menunjukkan animasi yang berjalan pada item yang menghilang dari penampung.
  • CHANGE_DISAPPEARING - Flag yang menunjukkan animasi yang berjalan pada item yang berubah karena item menghilang dari container.

Anda dapat menentukan animasi kustom Anda sendiri untuk keempat jenis peristiwa ini guna menyesuaikan tampilan transisi tata letak, atau langsung memberi tahu sistem animasi agar menggunakan animasi default.

Untuk menetapkan atribut android:animateLayoutchanges ke true untuk ViewGroup melakukan hal berikut:

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

Menyetel atribut ini ke true (benar) akan otomatis menganimasikan View yang ditambahkan atau dihapus dari ViewGroup serta View lainnya di ViewGroup.

Menganimasikan perubahan status tampilan menggunakan StateListAnimator

Class StateListAnimator memungkinkan Anda menentukan animator yang berjalan saat status tampilan berubah. Objek ini berperilaku sebagai wrapper untuk Objek Animator, memanggil animasi tersebut setiap kali ditentukan perubahan status tampilan (seperti perubahan "ditekan" atau "difokus").

StateListAnimator dapat ditentukan dalam resource XML dengan elemen <selector> root dan elemen <item> turunan yang masing-masing menentukan status tampilan berbeda yang ditentukan oleh class StateListAnimator. Setiap <item> berisi definisi untuk set animasi properti.

Misalnya, file berikut membuat animator daftar status yang mengubah skala x dan y tampilan saat ditekan:

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>

Untuk melampirkan animator daftar status ke tampilan, tambahkan atribut android:stateListAnimator sebagai berikut:

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

Sekarang, animasi yang ditentukan dalam animate_scale.xml digunakan saat status tombol ini berubah.

Atau, jika ingin menetapkan animator daftar status ke sebuah tampilan dalam kode Anda, gunakan metode AnimatorInflater.loadStateListAnimator(), dan tetapkan animator ke tampilan Anda menggunakan metode View.setStateListAnimator().

Atau, sebagai ganti menganimasikan properti tampilan, Anda dapat memutar animasi drawable antara perubahan status, menggunakan AnimatedStateListDrawable. Beberapa widget sistem di Android 5.0 menggunakan animasi ini secara default. Contoh berikut menunjukkan bagaimana untuk menentukan AnimatedStateListDrawable sebagai resource XML:

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

Menggunakan TypeEvaluator

Jika ingin menganimasikan jenis yang tidak dikenal oleh sistem Android, Anda dapat membuat evaluator sendiri dengan menerapkan antarmuka TypeEvaluator. Jenis yang dikenal oleh sistem Android adalah int, float, atau warna, yang didukung oleh jenis IntEvaluator, FloatEvaluator, dan ArgbEvaluator para evaluator.

Hanya ada satu metode yang dapat diterapkan di TypeEvaluator antarmuka, metode evaluate(). Hal ini memungkinkan animator yang Anda gunakan untuk menampilkan nilai yang sesuai untuk properti teranimasi di titik animasi saat ini. Class FloatEvaluator menunjukkan cara melakukannya:

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

Catatan: Saat ValueAnimator (atau ObjectAnimator) berjalan, fraksi berlalu saat ini akan dihitung dari animasi (nilai antara 0 dan 1) dan kemudian menghitung versi terinterpolasinya tergantung interpolator apa yang Anda gunakan. Fraksi terinterpolasi adalah apa yang diterima oleh TypeEvaluator melalui parameter fraction, sehingga Anda tidak perlu memperhitungkan interpolator saat menghitung nilai animasi.

Menggunakan Interpolator

Interpolator menentukan bagaimana nilai tertentu dalam animasi dihitung sebagai fungsi dari baik. Misalnya, Anda dapat menentukan animasi untuk terjadi secara linear di seluruh animasi, yang berarti animasi bergerak secara merata sepanjang waktu, atau Anda dapat menentukan animasi untuk menggunakan waktu non-linear, misalnya, menggunakan akselerasi atau deselerasi di awal atau akhir animasi.

Interpolator dalam sistem animasi menerima fraksi dari Animator yang mewakili waktu berlalu dari animasi tersebut. Interpolator memodifikasi fraksi ini agar sesuai dengan jenis animasi yang disediakan. Sistem Android menyediakan seperangkat interpolator umum di android.view.animation package. Jika tidak ada dari interpolator tersebut yang sesuai dengan kebutuhan, Anda dapat menerapkan antarmuka TimeInterpolator dan membuat interpolator Anda sendiri.

Sebagai contoh, cara interpolator default AccelerateDecelerateInterpolator dan LinearInterpolator menghitung fraksi terinterpolasi dibandingkan di bawah ini. LinearInterpolator tidak berpengaruh pada fraksi berlalu. AccelerateDecelerateInterpolator melaju cepat di awal animasi dan melambat di akhir animasi. Metode berikut menentukan logika untuk interpolator ini:

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

LinearInterpolator

Kotlin

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

Java

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

Tabel berikut menunjukkan nilai perkiraan yang dihitung oleh interpolator ini untuk sebuah animasi yang berlangsung selama 1.000 milidetik:

mdtk berlalu Fraksi berlalu/Fraksi terinterpolasi (Linear) Fraksi terinterpolasi (Akselerasi/Deselerasi)
0 0 0
200 0,2 0,1
400 0,4 0,345
600 .6 0,654
800 0,8 0,9
1000 1 1

Seperti ditunjukkan dalam tabel, LinearInterpolator mengubah nilai pada kecepatan yang sama, yaitu 0,2 untuk setiap 200 milidetik yang berlalu. AccelerateDecelerateInterpolator mengubah nilai lebih cepat daripada LinearInterpolator antara 200 md dan 600 md, dan lebih lambat antara 600 md dan 1.000 md.

Menentukan keyframe

Objek Keyframe terdiri dari pasangan waktu/nilai yang memungkinkan Anda menentukan status tertentu pada waktu tertentu untuk sebuah animasi. Setiap keyframe juga dapat memiliki interpolator untuk mengontrol perilaku animasi dalam interval antara waktu dan waktu keyframe ini.

Untuk membuat instance objek Keyframe, Anda harus menggunakan salah satu factory metode, ofInt(), ofFloat(), atau ofObject() untuk mendapatkan jenis Keyframe yang sesuai. Kemudian Anda memanggil metode factory ofKeyframe() untuk dapatkan objek PropertyValuesHolder. Setelah memiliki objek tersebut, Anda bisa dapatkan animator dengan meneruskan objek PropertyValuesHolder dan objek yang akan dianimasikan. Cuplikan kode berikut menunjukkan cara melakukannya:

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

Menganimasikan tampilan

Sistem animasi properti memungkinkan animasi objek dan penawaran View yang disederhanakan beberapa keunggulan dibandingkan sistem animasi tampilan. Sistem animasi tampilan mengubah objek View dengan mengubah cara objek tersebut digambar. Ini adalah ditangani di penampung setiap View, karena View itu sendiri tidak memiliki properti untuk dimanipulasi. Hasilnya, View dianimasikan, tetapi objek View itu sendiri tidak berubah. Hal ini menyebabkan perilaku seperti objek yang masih ada di lokasi aslinya, meskipun objek tersebut digambar di lokasi yang berbeda di layar. Di Android 3.0, properti baru dan metode pengambil dan penyetel terkait ditambahkan untuk menghilangkan kelemahan ini.

Sistem animasi properti dapat menganimasikan View di layar dengan mengubah properti sebenarnya dalam objek View. Selain itu, View juga otomatis memanggil metode invalidate() untuk memuat ulang layar setiap kali propertinya diubah. Properti baru di class View yang memfasilitasi animasi properti adalah:

  • translationX dan translationY: Properti ini mengontrol lokasi Tampilan terletak sebagai delta dari koordinat kiri dan atasnya yang disetel oleh tata letaknya container.
  • rotation, rotationX, dan rotationY: Properti ini mengontrol rotasi dalam 2D (properti rotation) dan 3D di sekitar titik pivot.
  • scaleX dan scaleY: Properti ini mengontrol penskalaan 2D View di sekitar titik pivotnya.
  • pivotX dan pivotY: Properti ini mengontrol lokasi titik pivot, yang memungkinkan terjadinya transformasi rotasi dan penskalaan. Secara default, pivot ini titik terletak di pusat objek.
  • x dan y: Ini adalah properti utilitas sederhana untuk menjelaskan lokasi akhir View dalam penampung, sebagai jumlah dari nilai kiri dan atas, serta nilai translationX dan translationY.
  • alpha: Menunjukkan transparansi alfa pada View. Nilai ini secara default adalah 1 (buram), dengan nilai 0 menunjukkan transparansi penuh (tidak terlihat).

Untuk menganimasikan properti objek View, seperti nilai warna atau rotasinya, Anda hanya perlu membuat animator properti dan menentukan properti View yang ingin Anda animasikan. Contoh:

Kotlin

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

Java

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

Untuk informasi selengkapnya tentang cara membuat animator, lihat bagian menganimasikan dengan ValueAnimator dan ObjectAnimator.

Menganimasikan dengan ViewPropertyAnimator

ViewPropertyAnimator menyediakan cara sederhana untuk menganimasikan beberapa properti View secara paralel, menggunakan satu Animator dasar . Perilaku objek ini sangat mirip dengan ObjectAnimator, yaitu dengan memodifikasi nilai sebenarnya properti tampilan, tetapi lebih efisien saat menganimasi banyak properti sekaligus. Selain itu, kode untuk menggunakan ViewPropertyAnimator jauh lebih ringkas dan lebih mudah dibaca. Cuplikan kode berikut menunjukkan perbedaan dalam menggunakan beberapa ObjectAnimator objek, satu ObjectAnimator, dan ViewPropertyAnimator saat secara bersamaan menganimasikan properti x dan y tampilan.

Beberapa ObjectAnimator

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

Satu ObjectAnimator

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

Untuk informasi selengkapnya tentang ViewPropertyAnimator, lihat postingan blog Developer Android yang terkait.

Mendeklarasikan animasi dalam XML

Sistem animasi properti memungkinkan Anda mendeklarasikan animasi properti dengan XML, bukan secara terprogram. Dengan menentukan animasi dalam XML, Anda dapat menggunakan kembali animasi di beberapa aktivitas dengan mudah, juga lebih mudah mengedit urutan animasi.

Untuk membedakan file animasi yang menggunakan API animasi properti baru dengan yang menggunakan framework animasi tampilan versi lama, mulai Android 3.1, Anda harus menyimpan file XML untuk animasi properti di direktori res/animator/.

Class animasi properti berikut memiliki dukungan deklarasi XML dengan elemen tag XML berikut:

Untuk menemukan atribut yang dapat Anda gunakan dalam deklarasi XML, lihat Resource animasi. Contoh berikut memutar dua set animasi objek secara berurutan, dengan kumpulan bertingkat pertama memutar dua animasi objek secara bersamaan:

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

Untuk menjalankan animasi ini, Anda harus meng-inflate resource XML dalam kode Anda ke objek AnimatorSet, lalu menetapkan objek target untuk semua animasi sebelum memulai set animasi tersebut. Demi kepraktisan, panggilan ke setTarget() akan menetapkan satu objek target untuk semua turunan AnimatorSet. Kode berikut menunjukkan cara melakukannya:

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

Anda juga dapat mendeklarasikan ValueAnimator dalam XML, sebagai yang ditunjukkan dalam contoh berikut:

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

Untuk menggunakan ValueAnimator sebelumnya dalam kode, Anda harus meng-inflate objek, menambahkan AnimatorUpdateListener, mendapatkan nilai animasi yang diperbarui, dan menggunakannya di properti salah satu tampilan Anda, seperti yang ditunjukkan pada kode berikut:

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

Untuk informasi tentang sintaksis XML untuk menentukan animasi properti, lihat Resource animasi .

Efek potensial pada performa UI

Animator yang memperbarui UI menyebabkan pekerjaan rendering ekstra untuk setiap frame tempat animasi dijalankan. Karena alasan ini, menggunakan animasi yang membutuhkan banyak resource dapat berdampak negatif terhadap performa aplikasi Anda.

Pekerjaan yang diperlukan untuk menganimasikan UI Anda ditambahkan ke tahap animasi pipeline rendering. Anda dapat mengetahui apakah animasi memengaruhi performa aplikasi atau tidak dengan mengaktifkan Rendering GPU Profil dan memantau tahap animasi. Untuk informasi selengkapnya, lihat Rendering GPU profil panduan kami.