Bergabunglah bersama kami di ⁠#Android11: The Beta Launch Show pada tanggal 3 Juni!

Menganimasikan gerakan menggunakan fisika pegas

Gerakan berbasis fisika didorong oleh gaya. Gaya pegas adalah salah satu gaya yang memandu interaktivitas dan gerakan. Gaya pegas memiliki sifat berikut: redaman dan kekakuan. Pada animasi berbasis pegas, nilai dan kecepatan dihitung berdasarkan gaya pegas yang diterapkan di setiap frame.

Jika Anda ingin animasi aplikasi melambat hanya dalam satu arah, pertimbangkan untuk menggunakan animasi fling berbasis gesekan.

Siklus animasi pegas

Pada animasi berbasis pegas, Anda dapat menggunakan class SpringForce untuk menyesuaikan kekakuan pegas, rasio redamannya, dan posisi akhirnya. Segera setelah animasi dimulai, gaya pegas akan memperbarui nilai animasi dan kecepatan di setiap frame. Animasi ini berlanjut hingga gaya pegas mencapai kesetimbangan.

Misalnya, jika Anda menarik ikon aplikasi mengitari layar lalu melepaskannya dengan mengangkat jari Anda dari ikon, ikon akan kembali ke tempatnya semula dengan gaya yang tak terlihat, tetapi familier.

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

Pelepasan pegas
Gambar 1. Efek pelepasan pegas

Membuat animasi pegas

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

Bagian berikut membahas langkah-langkah membuat animasi pegas secara mendetail.

Menambahkan support library

Untuk menggunakan support library berbasis fisika, Anda harus menambahkan support library tersebut ke project Anda sebagai berikut:

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

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

    Untuk melihat versi terbaru library ini, lihat informasi tentang DynamicAnimation di halaman versi.

Membuat animasi pegas

Anda dapat menggunakan class SpringAnimation untuk membuat animasi pegas untuk sebuah objek. Untuk membuat animasi pegas, Anda harus membuat instance untuk class SpringAnimation dan menyediakan sebuah objek, sebuah properti objek yang ingin Anda animasikan, dan sebuah posisi akhir pegas opsional tempat Anda ingin animasi berhenti.

Catatan: Pada saat membuat animasi pegas, posisi akhir pegas bersifat opsional. Namun, posisi akhir ini 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 properti sebenarnya di objek tampilan. Tampilan berikut tersedia di sistem:

  • ALPHA: Menunjukkan transparansi alfa pada tampilan. Nilai ini secara default adalah 1 (buram), dengan nilai 0 menunjukkan transparansi penuh (tidak terlihat).
  • TRANSLATION_X, TRANSLATION_Y, dan TRANSLATION_Z: Properti ini mengontrol lokasi tampilan sebagai delta dari koordinat kiri, koordinat atas, dan elevasi, yang ditetapkan oleh container tata letaknya.
  • ROTATION, ROTATION_X, dan ROTATION_Y: Properti ini mengontrol rotasi dalam 2D (properti rotation) dan 3D di sekitar titik pivot.
  • SCROLL_X dan SCROLL_Y: Properti ini menunjukkan offset scroll tepi kiri dan tepi atas sumber dalam piksel. Juga menunjukkan posisi dari segi banyaknya halaman yang di-scroll.
  • SCALE_X dan SCALE_Y: Properti ini mengontrol penskalaan 2D tampilan di sekitar titik pivotnya.
  • X, Y, dan Z: Ini adalah properti utilitas dasar untuk mendeskripsikan lokasi akhir tampilan dalam container-nya.

Mendaftarkan pemroses

Class DynamicAnimation menyediakan dua pemroses: OnAnimationUpdateListener dan OnAnimationEndListener. Pemroses ini memantau perubahan dalam animasi, misalnya saat ada nilai animasi yang berubah dan saat animasi berakhir.

OnAnimationUpdateListener

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

  1. Panggil metode addUpdateListener() dan hubungkan pemroses ke animasi.

    Catatan: Anda harus mendaftarkan pemroses pembaruan sebelum animasi dimulai. Tetapi, pemroses pembaruan sebaiknya hanya didaftarkan jika Anda memerlukan pembaruan per frame terkait perubahan nilai animasi. Pemroses pembaruan mencegah kemungkinan animasi berjalan di thread terpisah.

  2. Ganti metode onAnimationUpdate() untuk memberi tahu caller tentang perubahan pada objek saat ini. Contoh kode berikut mengilustrasikan penggunaan OnAnimationUpdateListener secara keseluruhan.

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 animasi. Anda dapat menyiapkan pemroses untuk menerima callback setiap kali animasi mencapai kesetimbangan atau dibatalkan. Untuk mendaftarkan pemroses, lakukan langkah-langkah berikut:

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

Menghapus pemroses

Untuk berhenti menerima callback pembaruan animasi dan callback akhir animasi, gunakan, berturut-turut metode removeUpdateListener() dan removeEndListener().

Menetapkan nilai awal animasi

Untuk menetapkan nilai awal animasi, panggil metode setStartValue() dan teruskan nilai awal animasi tersebut. Jika Anda tidak menetapkan nilai awal, animasi akan menggunakan nilai saat ini dari properti objek sebagai nilai awal.

Menetapkan rentang nilai animasi

Anda dapat menetapkan nilai animasi minimum dan maksimum jika ingin membatasi nilai properti ke rentang tertentu. Ada baiknya Anda juga mengontrol rentang ini jika menganimasikan properti yang memiliki rentang intrinsik, seperti alfa (dari 0 hingga 1).

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

Kedua metode ini menampilkan animasi yang nilainya ditetapkan.

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

Menetapkan kecepatan awal

Kecepatan awal menentukan kecepatan perubahan properti animasi di awal animasi. Kecepatan awal default ditetapkan ke nol piksel per detik. Anda dapat mengatur kecepatan ini dengan kecepatan gestur sentuh atau menggunakan nilai tetap sebagai kecepatan awal. Jika Anda memilih untuk memberikan nilai tetap, sebaiknya tentukan nilai tersebut dalam dp per detik, lalu konversi menjadi piksel per detik. Dengan menentukan nilai dalam dp per detik, kecepatan menjadi tidak bergantung pada kepadatan dan faktor bentuk. Untuk informasi selengkapnya tentang mengonversi nilai menjadi piksel per detik, lihat bagian Mengonversi dp per detik menjadi piksel per detik.

Untuk menetapkan kecepatan, panggil metode setStartVelocity() dan teruskan kecepatan dalam piksel per detik. Metode ini menampilkan objek gaya pegas yang kecepatannya ditetapkan.

Catatan: Gunakan metode class GestureDetector.OnGestureListener atau VelocityTracker untuk mengambil dan menghitung kecepatan gestur 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 menentukan awal kecepatan dalam nilai tetap, berikan nilai tersebut dalam dp per detik, lalu konversi menjadi piksel per detik. Untuk konversi, gunakan metode applyDimension() dari class TypedValue. Lihat contoh kode 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 metode getter dan setter untuk setiap properti pegas, seperti rasio redaman dan kekakuan. Untuk menetapkan properti pegas, penting untuk mengambil objek gaya pegas atau membuat gaya pegas kustom yang propertinya dapat Anda tetapkan. Untuk informasi selengkapnya tentang membuat gaya pegas kustom, lihat bagian Membuat gaya pegas kustom.

Tips: Saat menggunakan metode setter, Anda dapat membuat rantai metode karena semua metode setter menampilkan objek gaya pegas.

Rasio redaman

Rasio redaman menjelaskan berkurangnya ayunan pegas secara bertahap. Dengan rasio redaman, Anda dapat menentukan seberapa cepat ayunan melambat dari satu pantulan ke pantulan berikutnya. Ada empat cara untuk meredam pegas:

  • Overdamping (peredaman berlebih) terjadi jika rasio redaman lebih besar daripada satu. Akibatnya, objek kembali ke posisi diamnya dengan cepat.
  • Peredaman kritis terjadi jika rasio redaman sama dengan satu. Akibatnya, objek kembali ke posisi diam dalam waktu tersingkat yang mungkin.
  • Underdamping terjadi jika rasio redaman kurang dari satu. Akibatnya, objek melejit beberapa kali dengan melewatkan posisi diam, lalu secara bertahap mencapai posisi diamnya.
  • Tanpa redaman terjadi jika rasio redaman sama dengan nol. Akibatnya, objek berayun tanpa henti.

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

  1. Panggil metode getSpring() untuk mengambil pegas yang akan ditingkatkan rasio redamannya.
  2. Panggil metode setDampingRatio() dan teruskan rasio redaman yang ingin Anda tambahkan ke pegas. Metode ini menampilkan objek gaya pegas yang rasio redamannya ditetapkan.

    Catatan: Rasio redaman harus berupa bilangan selain negatif. Jika Anda menetapkan rasio redaman ke nol, pegas tidak akan pernah mencapai posisi diamnya. 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 pegas. Pegas yang kaku memberikan gaya lebih besar ke objek yang terhubung saat pegas tidak berada di posisi diam. Untuk menambahkan kekakuan ke pegas, lakukan langkah-langkah berikut:

  1. Panggil metode getSpring() untuk mengambil pegas yang akan ditingkatkan kekakuannya.
  2. Panggil metode setStiffness() dan teruskan nilai kekakuan yang ingin Anda tambahkan ke pegas. Metode ini menampilkan objek gaya pegas yang kekakuannya ditetapkan.

    Catatan: Kekakuan harus berupa 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 dari menggunakan gaya pegas default. Gaya pegas kustom memungkinkan Anda membagikan instance gaya pegas yang sama ke berbagai animasi pegas. Setelah membuat gaya pegas, 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 metode setSpring() untuk menetapkan pegas ke animasi.

    setSpring(force);

Memulai animasi

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

Metode animateToFinalPosition() menjalankan 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 arah animasi. Misalnya, dalam animasi pegas berantai, animasi satu tampilan bergantung pada tampilan lainnya. Untuk animasi seperti ini, akan lebih praktis jika Anda menggunakan metode 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, di mana animasi satu tampilan bergantung pada tampilan lainnya.

Demo pegas berantai
Gambar 10. Demo pegas berantai

Untuk menggunakan metode animateToFinalPosition(), panggil metode animateToFinalPosition() dan teruskan posisi diam pegas. Anda juga dapat menetapkan posisi diam pegas dengan memanggil metode setFinalPosition().

Metode start() tidak menetapkan nilai properti ke nilai awal dengan segera. Nilai properti berubah di setiap pulsa animasi, yang terjadi sebelum proses gambar. Akibatnya, perubahan ini tercermin dalam frame berikutnya, seolah-olah nilainya ditetapkan dengan segera.

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 ideal di mana Anda perlu membatalkan atau melompat ke akhir animasi adalah saat interaksi pengguna mengharuskan animasi untuk dihentikan segera. Hal ini terjadi terutama saat pengguna mendadak keluar dari aplikasi atau tampilan menjadi tidak terlihat.

Ada dua metode yang dapat Anda gunakan untuk menghentikan animasi. Metode cancel() mengakhiri animasi pada nilai di mana animasi itu berada. Metode skipToEnd() melewatkan animasi ke nilai akhir, lalu menghentikannya.

Sebelum Anda dapat menghentikan animasi, penting untuk memeriksa status pegas terlebih dahulu. Jika pegas tanpa redaman, animasi tidak akan pernah mencapai posisi diamnya. Untuk memeriksa status pegas, panggil metode canSkipToEnd(). Jika pegas diredam, metode akan menampilkan true. Jika sebaliknya, metode akan menampilkan false.

Setelah mengetahui status pegas, Anda dapat menghentikan animasi menggunakan metode skipToEnd() atau cancel(). Metode cancel() hanya boleh dipanggil dari thread utama.

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