Menyesuaikan animasi

Banyak Animation API biasanya menerima parameter untuk menyesuaikan perilakunya.

Menyesuaikan animasi dengan parameter AnimationSpec

Sebagian besar API animasi memungkinkan developer menyesuaikan spesifikasi animasi dengan parameter AnimationSpec opsional.

val alpha: Float by animateFloatAsState(
    targetValue = if (enabled) 1f else 0.5f,
    // Configure the animation duration and easing.
    animationSpec = tween(durationMillis = 300, easing = FastOutSlowInEasing),
    label = "alpha"
)

Ada berbagai jenis AnimationSpec untuk membuat berbagai jenis animasi.

Membuat animasi berbasis fisika dengan spring

spring membuat animasi berbasis fisika antara nilai awal dan akhir. Dibutuhkan 2 parameter: dampingRatio dan stiffness.

dampingRatio menentukan seberapa guncangan seharusnya. Nilai defaultnya adalah Spring.DampingRatioNoBouncy.

Gambar 1. Menetapkan rasio redaman pegas yang berbeda.

stiffness menentukan seberapa cepat spring akan bergerak menuju nilai akhir. Nilai defaultnya adalah Spring.StiffnessMedium.

Gambar 2. Menetapkan kekakuan pegas yang berbeda

val value by animateFloatAsState(
    targetValue = 1f,
    animationSpec = spring(
        dampingRatio = Spring.DampingRatioHighBouncy,
        stiffness = Spring.StiffnessMedium
    ),
    label = "spring spec"
)

spring dapat menangani gangguan secara lebih lancar daripada jenis AnimationSpec berbasis durasi karena dapat menjamin kontinuitas saat target berubah di tengah animasi. spring digunakan sebagai AnimationSpec default oleh banyak API animasi, seperti animate*AsState dan updateTransition.

Misalnya, jika kita menerapkan konfigurasi spring ke animasi berikut yang didorong oleh sentuhan pengguna, saat mengganggu animasi saat berlangsung, Anda dapat melihat bahwa penggunaan tween tidak merespons selancar menggunakan spring.

Gambar 3. Menetapkan spesifikasi tween vs spring untuk animasi, dan mengganggunya.

Menganimasikan antara nilai awal dan akhir dengan kurva easing dengan tween

tween menganimasikan antara nilai awal dan akhir pada durationMillis yang ditentukan menggunakan kurva easing. tween adalah singkatan dari kata between - karena berada di antara dua nilai.

Anda juga dapat menentukan delayMillis untuk menunda dimulainya animasi.

val value by animateFloatAsState(
    targetValue = 1f,
    animationSpec = tween(
        durationMillis = 300,
        delayMillis = 50,
        easing = LinearOutSlowInEasing
    ),
    label = "tween delay"
)

Lihat Easing untuk mengetahui informasi selengkapnya.

Menganimasikan ke nilai tertentu pada waktu tertentu dengan keyframes

keyframes dianimasikan berdasarkan nilai snapshot yang ditentukan pada stempel waktu yang berbeda dalam durasi animasi. Pada waktu tertentu, nilai animasi akan diinterpolasi antara dua nilai keyframe. Untuk setiap keyframe ini, Easing dapat ditentukan untuk menentukan kurva interpolasi.

Menentukan nilai pada 0 md dan pada waktu durasi bersifat opsional. Jika Anda tidak menentukan nilai ini, nilai default akan ditetapkan ke nilai awal dan akhir animasi.

val value by animateFloatAsState(
    targetValue = 1f,
    animationSpec = keyframes {
        durationMillis = 375
        0.0f at 0 using LinearOutSlowInEasing // for 0-15 ms
        0.2f at 15 using FastOutLinearInEasing // for 15-75 ms
        0.4f at 75 // ms
        0.4f at 225 // ms
    },
    label = "keyframe"
)

Mengulang animasi dengan repeatable

repeatable menjalankan animasi berbasis durasi (seperti tween atau keyframes) berulang kali hingga mencapai jumlah iterasi yang ditentukan. Anda dapat meneruskan parameter repeatMode untuk menentukan apakah animasi harus diulang dengan memulai dari awal (RepeatMode.Restart) atau dari akhir (RepeatMode.Reverse).

val value by animateFloatAsState(
    targetValue = 1f,
    animationSpec = repeatable(
        iterations = 3,
        animation = tween(durationMillis = 300),
        repeatMode = RepeatMode.Reverse
    ),
    label = "repeatable spec"
)

Mengulangi animasi tanpa batas dengan infiniteRepeatable

infiniteRepeatable seperti repeatable, tetapi berulang untuk jumlah iterasi yang tak terbatas.

val value by animateFloatAsState(
    targetValue = 1f,
    animationSpec = infiniteRepeatable(
        animation = tween(durationMillis = 300),
        repeatMode = RepeatMode.Reverse
    ),
    label = "infinite repeatable"
)

Dalam pengujian menggunakan ComposeTestRule, animasi yang menggunakan infiniteRepeatable tidak dijalankan. Komponen akan dirender menggunakan nilai awal setiap nilai animasi.

Langsung snap ke nilai akhir dengan snap

snap adalah AnimationSpec khusus yang langsung mengalihkan nilai ke nilai akhir. Anda dapat menentukan delayMillis untuk menunda awal animasi.

val value by animateFloatAsState(
    targetValue = 1f,
    animationSpec = snap(delayMillis = 50),
    label = "snap spec"
)

Menetapkan fungsi easing kustom

Operasi AnimationSpec berbasis durasi (seperti tween atau keyframes) menggunakan Easing untuk menyesuaikan fraksi animasi. Dengan cara ini, nilai animasi dapat dipercepat dan diperlambat, dibandingkan bergerak pada tingkat konstan. Fraksi adalah nilai antara 0 (awal) dan 1,0 (akhir) yang menunjukkan titik saat ini dalam animasi.

Easing sebenarnya merupakan fungsi yang mengambil nilai fraksi antara 0 dan 1,0 dan menampilkan float. Nilai yang ditampilkan dapat berada di luar batas untuk mewakili overshoot atau undershoot. Easing kustom dapat dibuat seperti kode di bawah.

val CustomEasing = Easing { fraction -> fraction * fraction }

@Composable
fun EasingUsage() {
    val value by animateFloatAsState(
        targetValue = 1f,
        animationSpec = tween(
            durationMillis = 300,
            easing = CustomEasing
        ),
        label = "custom easing"
    )
    // ……
}

Compose menyediakan beberapa fungsi Easing bawaan yang mencakup sebagian besar kasus penggunaan. Lihat Kecepatan - Desain Material untuk mengetahui informasi selengkapnya tentang Easing yang akan digunakan bergantung pada skenario Anda.

  • FastOutSlowInEasing
  • LinearOutSlowInEasing
  • FastOutLinearEasing
  • LinearEasing
  • CubicBezierEasing
  • Selengkapnya

Menganimasikan jenis data kustom dengan mengonversi ke dan dari AnimationVector

Sebagian besar Compose API animasi mendukung Float, Color, Dp, dan jenis data dasar lainnya sebagai nilai animasi secara default, tetapi terkadang Anda perlu menganimasikan jenis data lain termasuk yang khusus. Selama animasi, nilai animasi apa pun akan direpresentasikan sebagai AnimationVector. Nilai ini dikonversi menjadi AnimationVector dan sebaliknya oleh TwoWayConverter yang terkait sehingga sistem animasi inti dapat menanganinya secara seragam. Misalnya, Int direpresentasikan sebagai AnimationVector1D yang memiliki satu nilai float. TwoWayConverter untuk Int terlihat seperti ini:

val IntToVector: TwoWayConverter<Int, AnimationVector1D> =
    TwoWayConverter({ AnimationVector1D(it.toFloat()) }, { it.value.toInt() })

Color pada dasarnya adalah kumpulan 4 nilai, merah, hijau, biru, dan alfa, sehingga Color dikonversi menjadi AnimationVector4D yang menyimpan 4 nilai float. Dengan cara ini, setiap jenis data yang digunakan dalam animasi dikonversi menjadi AnimationVector1D, AnimationVector2D, AnimationVector3D, atau AnimationVector4D bergantung pada dimensinya. Hal ini memungkinkan berbagai komponen objek dianimasikan secara independen, masing-masing dengan pelacakan kecepatannya sendiri. Converter bawaan untuk jenis data dasar dapat diakses menggunakan converter seperti Color.VectorConverter atau Dp.VectorConverter.

Jika ingin menambahkan dukungan untuk jenis data baru sebagai nilai animasi, Anda dapat membuat TwoWayConverter Anda sendiri dan menyediakannya ke API. Misalnya, Anda dapat menggunakan animateValueAsState untuk menganimasikan jenis data kustom seperti ini:

data class MySize(val width: Dp, val height: Dp)

@Composable
fun MyAnimation(targetSize: MySize) {
    val animSize: MySize by animateValueAsState(
        targetSize,
        TwoWayConverter(
            convertToVector = { size: MySize ->
                // Extract a float value from each of the `Dp` fields.
                AnimationVector2D(size.width.value, size.height.value)
            },
            convertFromVector = { vector: AnimationVector2D ->
                MySize(vector.v1.dp, vector.v2.dp)
            }
        ),
        label = "size"
    )
}

Daftar berikut menyertakan beberapa VectorConverter bawaan: