Menganimasikan gerakan menggunakan fisika pegas

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

Berbasis fisika gerakan yang didorong oleh gaya. Gaya pegas adalah salah satu gaya yang mengarahkan interaktivitas dan {i>motion.<i} Gaya pegas memiliki sifat berikut: redaman dan kekakuan. Dalam animasi berbasis pegas, nilai dan kecepatan dihitung berdasarkan gaya pegas yang diterapkan pada masing-masing {i>frame<i}.

Jika Anda ingin animasi aplikasi melambat hanya dalam satu arah, pertimbangkan untuk menggunakan model animasi fling sebagai gantinya.

Siklus animasi pegas

Dalam animasi berbasis pegas, SpringForce memungkinkan Anda menyesuaikan kekakuan pegas, rasio redamannya, dan posisi akhir. Segera setelah animasi dimulai, gaya pegas diperbarui nilai animasi dan kecepatan pada setiap {i>frame<i}. Animasi berlanjut sampai gaya pegas mencapai kesetimbangan.

Misalnya, jika Anda menarik ikon aplikasi mengitari layar, lalu melepaskannya dengan mengangkat jari Anda dari ikon, ikon akan kembali ke aslinya dengan kekuatan yang tak terlihat tetapi bisa dikenali.

Gambar 1 memperlihatkan efek pegas yang serupa. Tanda plus (+) di di tengah lingkaran menunjukkan gaya yang diterapkan melalui gestur sentuh.

Pelepasan pegas
Gambar 1. Efek pelepasan pegas

Membuat animasi pegas

Langkah-langkah umum untuk membangun animasi pegas untuk aplikasi Anda adalah sebagai berikut:

Bagian berikut membahas langkah-langkah umum membangun pegas animasi secara rinci.

Menambahkan support library

Untuk menggunakan pustaka dukungan berbasis fisika, Anda harus menambahkan pustaka dukungan ke proyek Anda sebagai berikut:

  1. Buka file build.gradle untuk modul aplikasi Anda.
  2. Tambahkan support library ke bagian dependencies.

    Groovy

            dependencies {
                def dynamicanimation_version = '1.0.0'
                implementation "androidx.dynamicanimation:dynamicanimation:$dynamicanimation_version"
            }
            

    Kotlin

            dependencies {
                val dynamicanimation_version = "1.0.0"
                implementation("androidx.dynamicanimation:dynamicanimation:$dynamicanimation_version")
            }
            

    Untuk melihat versi terbaru untuk library ini, lihat informasi tentang Animasi dinamis pada halaman versi.

Membuat animasi pegas

Class SpringAnimation memungkinkan Anda membuat animasi pegas untuk sebuah objek. Untuk membuat animasi pegas, Anda harus membuat instance SpringAnimation dan berikan objek, properti objek yang ingin dianimasikan, dan posisi pegas akhir opsional tempat Anda ingin animasi berhenti.

Catatan: Pada saat membuat animasi pegas, elemen akhir posisi pegas bersifat opsional. Namun, ID harus ditentukan sebelum memulai animasi.

Kotlin

val springAnim = findViewById<View>(R.id.imageView).let { img ->
    // Setting up a spring animation to animate the view’s translationY property with the final
    // spring position at 0.
    SpringAnimation(img, DynamicAnimation.TRANSLATION_Y, 0f)
}

Java

final View img = findViewById(R.id.imageView);
// Setting up a spring animation to animate the view’s translationY property with the final
// spring position at 0.
final SpringAnimation springAnim = new SpringAnimation(img, DynamicAnimation.TRANSLATION_Y, 0);

Animasi berbasis pegas dapat menganimasikan tampilan di layar dengan mengubah elemen properti aktual dalam objek tampilan. Tampilan berikut tersedia di sistem:

  • ALPHA: Menampilkan transparansi alfa pada tampilan. Nilainya adalah 1 (buram) dengan default, dengan nilai 0 yang menunjukkan transparansi penuh (tidak terlihat).
  • TRANSLATION_X, TRANSLATION_Y dan TRANSLATION_Z: Ini properti mengontrol lokasi tampilan sebagai delta dari sisi kirinya koordinat, koordinat atas, dan ketinggian, yang diatur oleh tata letaknya container.
  • ROTATION, ROTATION_X dan ROTATION_Y: Ini properti mengontrol rotasi dalam 2D (properti rotation) dan 3D di sekitar titik pivot.
  • SCROLL_X dan SCROLL_Y: Ini properti menunjukkan offset scroll dari tepi kiri dan tepi atas sumber dalam piksel. Ini juga menunjukkan posisi dalam hal seberapa besar di-scroll.
  • SCALE_X dan SCALE_Y: Ini mengontrol penskalaan 2D tampilan di sekitar titik pivotnya.
  • X, Y dan Z: Ini adalah dasar properti utilitas untuk menjelaskan lokasi akhir tampilan dalam container.

Mendaftarkan pemroses

Class DynamicAnimation menyediakan dua pendengar: OnAnimationUpdateListener dan OnAnimationEndListener. Pemroses ini memproses pembaruan dalam animasi seperti ketika ada perubahan nilai animasi dan kapan animasi berakhir.

OnAnimationUpdateListener

Jika ingin menganimasikan beberapa tampilan untuk membuat animasi berantai, Anda dapat menyiapkan OnAnimationUpdateListener menerima callback setiap kali terjadi perubahan pada metode saat ini. Callback memberi tahu tampilan lain untuk memperbarui posisi pegasnya berdasarkan perubahan yang ditimbulkan dalam properti tampilan saat ini. Untuk mendaftarkan pemroses, lakukan langkah-langkah berikut:

  1. Panggil addUpdateListener() dan melampirkan pemroses ke animasi.

    Catatan: Anda harus mendaftarkan update sebelum animasi dimulai. Meskipun demikian, pemroses pembaruan seharusnya hanya didaftarkan jika Anda memerlukan pembaruan nilai animasi per frame perubahan. Pemroses pembaruan mencegah animasi berpotensi yang berjalan di thread terpisah.

  2. Mengganti onAnimationUpdate() untuk memberi tahu pemanggil tentang perubahan pada objek saat ini. Tujuan kode contoh berikut mengilustrasikan penggunaan OnAnimationUpdateListener.

Kotlin

// Setting up a spring animation to animate the view1 and view2 translationX and translationY properties
val (anim1X, anim1Y) = findViewById<View>(R.id.view1).let { view1 ->
    SpringAnimation(view1, DynamicAnimation.TRANSLATION_X) to
            SpringAnimation(view1, DynamicAnimation.TRANSLATION_Y)
}
val (anim2X, anim2Y) = findViewById<View>(R.id.view2).let { view2 ->
    SpringAnimation(view2, DynamicAnimation.TRANSLATION_X) to
            SpringAnimation(view2, DynamicAnimation.TRANSLATION_Y)
}

// Registering the update listener
anim1X.addUpdateListener { _, value, _ ->
    // Overriding the method to notify view2 about the change in the view1’s property.
    anim2X.animateToFinalPosition(value)
}

anim1Y.addUpdateListener { _, value, _ -> anim2Y.animateToFinalPosition(value) }

Java

// Creating two views to demonstrate the registration of the update listener.
final View view1 = findViewById(R.id.view1);
final View view2 = findViewById(R.id.view2);

// Setting up a spring animation to animate the view1 and view2 translationX and translationY properties
final SpringAnimation anim1X = new SpringAnimation(view1,
        DynamicAnimation.TRANSLATION_X);
final SpringAnimation anim1Y = new SpringAnimation(view1,
    DynamicAnimation.TRANSLATION_Y);
final SpringAnimation anim2X = new SpringAnimation(view2,
        DynamicAnimation.TRANSLATION_X);
final SpringAnimation anim2Y = new SpringAnimation(view2,
        DynamicAnimation.TRANSLATION_Y);

// Registering the update listener
anim1X.addUpdateListener(new DynamicAnimation.OnAnimationUpdateListener() {

// Overriding the method to notify view2 about the change in the view1’s property.
    @Override
    public void onAnimationUpdate(DynamicAnimation dynamicAnimation, float value,
                                  float velocity) {
        anim2X.animateToFinalPosition(value);
    }
});

anim1Y.addUpdateListener(new DynamicAnimation.OnAnimationUpdateListener() {

  @Override
    public void onAnimationUpdate(DynamicAnimation dynamicAnimation, float value,
                                  float velocity) {
        anim2Y.animateToFinalPosition(value);
    }
});

OnAnimationEndListener

OnAnimationEndListener memberitahukan akhir suatu animasi. Anda dapat menyiapkan pemroses untuk menerima setiap kali animasi mencapai kesetimbangan atau dibatalkan. Kepada daftarkan pemroses, lakukan langkah-langkah berikut:

  1. Panggil addEndListener() dan melampirkan pemroses ke animasi.
  2. Mengganti onAnimationEnd() metode untuk menerima notifikasi setiap kali animasi mencapai kesetimbangan atau dibatalkan.

Menghapus pemroses

Untuk berhenti menerima callback pembaruan animasi dan callback akhir animasi, telepon removeUpdateListener() dan removeEndListener() masing-masing.

Menetapkan nilai awal animasi

Untuk mengatur nilai awal animasi, panggil metode setStartValue() dan meneruskan nilai awal animasi. Jika Anda tidak menyetel nilai awal, animasi akan menggunakan nilai properti objek saat ini sebagai nilai awal.

Menetapkan rentang nilai animasi

Anda dapat menetapkan nilai animasi minimum dan maksimum saat Anda ingin membatasi nilai properti ke rentang tertentu. Hal ini juga membantu untuk mengontrol rentang jika Anda menganimasikan properti yang memiliki rentang intrinsik, seperti {i>alpha<i} (dari 0 ke 1).

  • Untuk menetapkan nilai minimum, panggil metode setMinValue() dan meneruskan nilai minimum properti.
  • Untuk menetapkan nilai maksimum, panggil setMaxValue() dan meneruskan nilai maksimum properti.

Kedua metode ini menampilkan animasi yang nilainya ditetapkan.

Catatan: Jika Anda telah menetapkan nilai awal dan memiliki ditentukan rentang nilai animasi, pastikan nilai awal berada dalam rentang nilai minimum dan maksimum.

Menetapkan kecepatan awal

Kecepatan awal menentukan kecepatan perubahan properti animasi awal animasi. Kecepatan awal default ditetapkan ke nol {i>pixel<i} per detik. Anda dapat mengatur kecepatan dengan kecepatan sentuhan {i>gesture <i}atau dengan menggunakan nilai tetap sebagai kecepatan awal. Jika Anda memilih untuk memberikan nilai tetap, sebaiknya tentukan nilai dalam dp per detik dan kemudian mengubahnya menjadi {i>pixel<i} per detik. Menentukan nilai dalam dp per detik memungkinkan kecepatan menjadi independen dari kepadatan dan faktor bentuk. Untuk selengkapnya informasi tentang mengonversi nilai menjadi piksel per detik, lihat Mengonversi dp per detik menjadi piksel per detik bagian.

Untuk mengatur kecepatan, panggil metode setStartVelocity() dan meneruskan kecepatan dalam {i>pixel<i} per detik. Metode ini menampilkan sebuah benda gaya pegas yang kecepatannya ditetapkan.

Catatan: Gunakan GestureDetector.OnGestureListener atau Metode class VelocityTracker untuk mengambil dan menghitung kecepatan dari {i>gesture <i}sentuh.

Kotlin

findViewById<View>(R.id.imageView).also { img ->
    SpringAnimation(img, DynamicAnimation.TRANSLATION_Y).apply {
        …
        // Compute velocity in the unit pixel/second
        vt.computeCurrentVelocity(1000)
        val velocity = vt.yVelocity
        setStartVelocity(velocity)
    }
}

Java

final View img = findViewById(R.id.imageView);
final SpringAnimation anim = new SpringAnimation(img, DynamicAnimation.TRANSLATION_Y);
…
// Compute velocity in the unit pixel/second
vt.computeCurrentVelocity(1000);
float velocity = vt.getYVelocity();
anim.setStartVelocity(velocity);

Mengonversi dp per detik menjadi piksel per detik

Kecepatan pegas harus ditetapkan dalam piksel per detik. Jika Anda memilih untuk memberikan nilai tetap sebagai awal kecepatan, berikan nilai dalam dp per detik dan kemudian mengubahnya menjadi {i>pixel<i} per detik. Untuk konversi, gunakan applyDimension() dari class TypedValue. Lihat kode contoh berikut:

Kotlin

val pixelPerSecond: Float =
    TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpPerSecond, resources.displayMetrics)

Java

float pixelPerSecond = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpPerSecond, getResources().getDisplayMetrics());

Menetapkan properti pegas

Class SpringForce menentukan pengambil dan metode penyetel untuk setiap properti pegas, seperti redaman dan kekakuan. Untuk menetapkan properti pegas, penting untuk mengambil objek gaya pegas atau membuat gaya pegas kustom di mana Anda dapat mengatur properti. Untuk informasi selengkapnya tentang cara membuat gaya pegas, mengacu pada Membuat gaya pegas kustom bagian.

Tips: Saat menggunakan metode penyetel, Anda dapat membuat rantai metode karena semua metode penyetel mengembalikan gaya pegas .

Rasio redaman

Rasio redaman menjelaskan berkurangnya ayunan pegas secara bertahap. Menurut menggunakan rasio redaman, Anda dapat menentukan seberapa cepat peluruhan osilasi dari satu pantulan ke pantulan berikutnya. Ada empat cara berbeda untuk melembapkan musim semi:

  • Overdamping (peredaman berlebih) terjadi jika rasio redaman lebih besar daripada satu. Memungkinkan objek perlahan kembali ke posisi istirahat.
  • Peredaman kritis terjadi jika rasio redaman sama dengan satu. Memungkinkan objek kembali ke posisi istirahat dalam waktu yang tersingkat.
  • Underdamping terjadi jika rasio redaman kurang dari satu. Memungkinkan objek melejit berkali-kali dengan meneruskan posisi istirahat, kemudian secara bertahap mencapai posisi istirahat.
  • Tanpa redaman terjadi jika rasio redaman sama dengan nol. Fungsi ini memungkinkan berosilasi selamanya.

Untuk menambahkan rasio redaman ke pegas, lakukan langkah-langkah berikut:

  1. Panggil getSpring() untuk mengambil pegas untuk menambahkan rasio redaman.
  2. Panggil setDampingRatio() dan meneruskan rasio redaman yang ingin Anda tambahkan ke pegas. Tujuan menampilkan objek gaya pegas yang rasio redamannya ditetapkan.

    Catatan: Rasio redaman harus berupa bilangan non-negatif. Jika Anda mengatur rasio redaman ke nol, pegas akan tidak pernah mencapai posisi istirahat. Dengan kata lain, pegas terus-menerus berayun.

Konstanta rasio redaman berikut tersedia dalam sistem:

Gambar 2: Pantulan tinggi

Gambar 3: Pantulan sedang

Gambar 4: Pantulan rendah

Gambar 5: Tanpa pantulan

Rasio redaman default ditetapkan ke DAMPING_RATIO_MEDIUM_BOUNCY.

Kotlin

findViewById<View>(R.id.imageView).also { img ->
    SpringAnimation(img, DynamicAnimation.TRANSLATION_Y).apply {
        …
        // Setting the damping ratio to create a low bouncing effect.
        spring.dampingRatio = SpringForce.DAMPING_RATIO_LOW_BOUNCY
        …
    }
}

Java

final View img = findViewById(R.id.imageView);
final SpringAnimation anim = new SpringAnimation(img, DynamicAnimation.TRANSLATION_Y);
…
// Setting the damping ratio to create a low bouncing effect.
anim.getSpring().setDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY);
…

Kekakuan

Kekakuan menentukan konstanta pegas, yang mengukur kekuatan musim semi. Pegas yang kaku memberikan gaya lebih besar ke benda yang melekat ketika pegas tidak berada di posisi istirahat. Untuk menambahkan kekakuan ke pegas, lakukan langkah-langkah berikut:

  1. Panggil getSpring() untuk mengambil pegas untuk menambahkan kekakuan.
  2. Panggil setStiffness() dan meneruskan nilai kekakuan yang ingin Anda tambahkan ke pegas. Tujuan mengembalikan objek gaya pegas yang kekakuannya ditetapkan.

    Catatan: Kekakuan harus bilangan positif.

Konstanta kekakuan berikut tersedia dalam sistem:

Gambar 6: Kekakuan tinggi

Gambar 7: Kekakuan sedang

Gambar 8: Kekakuan rendah

Gambar 9: Kekakuan sangat rendah

Kekakuan default ditetapkan ke STIFFNESS_MEDIUM.

Kotlin

findViewById<View>(R.id.imageView).also { img ->
    SpringAnimation(img, DynamicAnimation.TRANSLATION_Y).apply {
        …
        // Setting the spring with a low stiffness.
        spring.stiffness = SpringForce.STIFFNESS_LOW
        …
    }
}

Java

final View img = findViewById(R.id.imageView);
final SpringAnimation anim = new SpringAnimation(img, DynamicAnimation.TRANSLATION_Y);
…
// Setting the spring with a low stiffness.
anim.getSpring().setStiffness(SpringForce.STIFFNESS_LOW);
…

Membuat gaya pegas kustom

Anda dapat membuat gaya pegas kustom sebagai alternatif untuk menggunakan gaya default gaya pegas. Gaya pegas kustom memungkinkan Anda berbagi gaya pegas yang sama di beberapa animasi pegas. Setelah Anda membuat pegas gaya, Anda dapat menetapkan properti seperti rasio redaman dan kekakuan.

  1. Buat objek SpringForce.

    SpringForce force = new SpringForce();

  2. Tetapkan properti dengan memanggil metode yang terkait. Anda juga dapat membuat rantai metode.

    force.setDampingRatio(DAMPING_RATIO_LOW_BOUNCY).setStiffness(STIFFNESS_LOW);

  3. Panggil setSpring() untuk menyetel pegas ke animasi.

    setSpring(force);

Mulai animasi

Ada dua cara untuk memulai animasi pegas: Dengan memanggil metode start() atau dengan memanggil animateToFinalPosition() . Kedua metode ini harus dipanggil di thread utama.

animateToFinalPosition() melakukan dua tugas:

  • Menetapkan posisi akhir pegas.
  • Memulai animasi, jika belum dimulai.

Karena metode ini memperbarui posisi akhir pegas dan memulai animasi jika diperlukan, Anda dapat memanggil metode ini kapan saja untuk mengubah kursus animasi. Misalnya, dalam animasi pegas berantai, animasi dari satu tampilan bergantung pada tampilan yang lain. Untuk animasi seperti ini, mudah untuk menggunakan animateToFinalPosition() . Dengan menggunakan metode ini dalam animasi pegas berantai, Anda tidak perlu khawatir jika animasi yang ingin Anda perbarui berikutnya sedang berjalan.

Gambar 10 mengilustrasikan animasi pegas berantai, dengan animasi satu tampilan bergantung pada tampilan lainnya.

Demo pegas berantai
Gambar 10. Demo pegas berantai

Untuk menggunakan animateToFinalPosition() , panggil metode animateToFinalPosition() dan meneruskan posisi istirahat dari pegas. Anda juga dapat menyetel semua hal lainnya posisi pegas dengan memanggil setFinalPosition() .

Metode start() melakukan tidak langsung menetapkan nilai properti ke nilai awal. Properti perubahan nilai di setiap pulsa animasi, yang terjadi sebelum operasi gambar diteruskan. Hasilnya, perubahan tercermin dalam {i>frame<i} berikutnya, seolah-olah nilainya langsung ditetapkan.

Kotlin

findViewById<View>(R.id.imageView).also { img ->
    SpringAnimation(img, DynamicAnimation.TRANSLATION_Y).apply {
        …
        // Starting the animation
        start()
        …
    }
}

Java

final View img = findViewById(R.id.imageView);
final SpringAnimation anim = new SpringAnimation(img, DynamicAnimation.TRANSLATION_Y);
…
// Starting the animation
anim.start();
…

Membatalkan animasi

Anda dapat membatalkan atau melompat ke bagian akhir animasi. Situasi yang ideal di mana Anda harus membatalkan atau melewati ke akhir adegan adalah ketika pengguna interaksi ini mengharuskan animasi segera dihentikan. Ini adalah kebanyakan ketika pengguna tiba-tiba keluar dari aplikasi atau tampilan menjadi tidak terlihat.

Ada dua metode yang dapat Anda gunakan untuk menghentikan animasi. Metode cancel() mengakhiri animasi pada nilai tempatnya berada. Tujuan Metode skipToEnd() melewati animasi ke nilai akhir, lalu menghentikannya.

Sebelum Anda dapat menghentikan animasi, penting untuk memeriksa terlebih dahulu status pegas. Jika status tidak diredam, animasi tidak dapat mencapai posisi istirahatnya. Untuk memeriksa status pegas, panggil metode Metode canSkipToEnd(). Jika pegas diredam, metode akan menampilkan true, jika tidak false.

Setelah Anda mengetahui status pegas, Anda bisa menghentikan animasi dengan menggunakan Metode skipToEnd() atau Metode cancel(). Tujuan cancel() metode harus dipanggil hanya di thread utama.

Catatan: Secara umum, Penyebab metode skipToEnd() lompatan visual.