Animasyon değiştiricileri ve kompozit öğeleri

E-posta yazma özelliği, animasyonla ilgili yaygın kullanım alanlarının yönetilmesi için yerleşik composable'lar ve değiştiriciler içerir.

Yerleşik animasyonlu composable'lar

AnimatedVisibility ile görünümü ve ortadan kayboluşunu canlandırın

Kendini gösteren ve gizlenen yeşil composable
Şekil 1. Sütundaki bir öğenin görünümünü ve kaybolmasını canlandırma

AnimatedVisibility composable, içeriğinin görünümünü ve kaybolmasını canlandırır.

var visible by remember {
    mutableStateOf(true)
}
// Animated visibility will eventually remove the item from the composition once the animation has finished.
AnimatedVisibility(visible) {
    // your composable here
    // ...
}

İçerik varsayılan olarak şeffaflaşarak ve genişleyerek görünür, solarak ve küçülerek kaybolur. Geçiş, EnterTransition ve ExitTransition belirtilerek özelleştirilebilir.

var visible by remember { mutableStateOf(true) }
val density = LocalDensity.current
AnimatedVisibility(
    visible = visible,
    enter = slideInVertically {
        // Slide in from 40 dp from the top.
        with(density) { -40.dp.roundToPx() }
    } + expandVertically(
        // Expand from the top.
        expandFrom = Alignment.Top
    ) + fadeIn(
        // Fade in with the initial alpha of 0.3f.
        initialAlpha = 0.3f
    ),
    exit = slideOutVertically() + shrinkVertically() + fadeOut()
) {
    Text("Hello", Modifier.fillMaxWidth().height(200.dp))
}

Yukarıdaki örnekte görebileceğiniz gibi, birden fazla EnterTransition veya ExitTransition nesnesini bir + operatörüyle birleştirebilirsiniz ve her biri, davranışını özelleştirmek için isteğe bağlı parametreleri kabul eder. Daha fazla bilgi için referanslara göz atın.

EnterTransition ve ExitTransition örnekleri

Geçiş Girişi ExitTransition
fadeIn
animasyonda kararma
fadeOut
kararma animasyonu
slideIn
slayt animasyon
slideOut
kaydırma animasyonu
slideInHorizontally
yatay kaydırma animasyonu
slideOutHorizontally
yatay kaydırma animasyonu
slideInVertically
dikey animasyonda kaydır
slideOutVertically
dikey kaydırma animasyonu
scaleIn
animasyonda ölçekleme
scaleOut
animasyonun ölçeğini genişletme
expandIn
animasyonda genişlet
shrinkOut
küçültme animasyonu
expandHorizontally
yatay olarak genişletme animasyonu
shrinkHorizontally
yatay olarak küçült animasyonu
expandVertically
dikey genişletme animasyonu
shrinkVertically
dikey olarak küçültme animasyonu

AnimatedVisibility, MutableTransitionState alan bir varyant da sunuyor. Böylece, AnimatedVisibility öğesi bileşim ağacına eklenir eklenmez bir animasyonu tetikleyebilirsiniz. Animasyon durumunu gözlemlemek için de faydalıdır.

// Create a MutableTransitionState<Boolean> for the AnimatedVisibility.
val state = remember {
    MutableTransitionState(false).apply {
        // Start the animation immediately.
        targetState = true
    }
}
Column {
    AnimatedVisibility(visibleState = state) {
        Text(text = "Hello, world!")
    }

    // Use the MutableTransitionState to know the current animation state
    // of the AnimatedVisibility.
    Text(
        text = when {
            state.isIdle && state.currentState -> "Visible"
            !state.isIdle && state.currentState -> "Disappearing"
            state.isIdle && !state.currentState -> "Invisible"
            else -> "Appearing"
        }
    )
}

Çocukların giriş ve çıkışını canlandırma

AnimatedVisibility kapsamındaki içerik (doğrudan veya dolaylı alt öğeler), animateEnterExit değiştiricisini kullanarak her biri için farklı animasyon davranışları belirtebilir. Bu alt öğelerin her biri için görsel efekt, AnimatedVisibility composable'ında belirtilen animasyonlar ile alt çocuğun kendi giriş/çıkış animasyonlarının kombinasyonudur.

var visible by remember { mutableStateOf(true) }

AnimatedVisibility(
    visible = visible,
    enter = fadeIn(),
    exit = fadeOut()
) {
    // Fade in/out the background and the foreground.
    Box(Modifier.fillMaxSize().background(Color.DarkGray)) {
        Box(
            Modifier
                .align(Alignment.Center)
                .animateEnterExit(
                    // Slide in/out the inner box.
                    enter = slideInVertically(),
                    exit = slideOutVertically()
                )
                .sizeIn(minWidth = 256.dp, minHeight = 64.dp)
                .background(Color.Red)
        ) {
            // Content of the notification…
        }
    }
}

Bazı durumlarda, çocukların animateEnterExit tarihine kadar her birinin kendi farklı animasyonlarını olabilmesi için AnimatedVisibility animasyon uygulamamasını isteyebilirsiniz. Bunun için AnimatedVisibility composable'da EnterTransition.None ve ExitTransition.None öğelerini belirtin.

Özel animasyon ekle

Yerleşik giriş ve çıkış animasyonlarının ötesine özel animasyon efektleri eklemek istiyorsanız AnimatedVisibility için içerik lambdasının içindeki transition özelliği aracılığıyla temel Transition örneğine erişin. Geçiş örneğine eklenen tüm animasyon durumları, AnimatedVisibility öğesinin giriş ve çıkış animasyonlarıyla eş zamanlı olarak çalışır. AnimatedVisibility, içeriğini kaldırmadan önce Transition içindeki tüm animasyonların tamamlanmasını bekler. Transition bağımsız olarak oluşturulan (animate*AsState kullanılarak gibi) çıkış animasyonları için AnimatedVisibility bunları dikkate alamaz ve bu nedenle tamamlanmadan önce composable içeriğini kaldırabilir.

var visible by remember { mutableStateOf(true) }

AnimatedVisibility(
    visible = visible,
    enter = fadeIn(),
    exit = fadeOut()
) { // this: AnimatedVisibilityScope
    // Use AnimatedVisibilityScope#transition to add a custom animation
    // to the AnimatedVisibility.
    val background by transition.animateColor(label = "color") { state ->
        if (state == EnterExitState.Visible) Color.Blue else Color.Gray
    }
    Box(modifier = Modifier.size(128.dp).background(background))
}

Transition ile ilgili ayrıntılar için updateTransition bölümüne bakın.

AnimatedContent ile hedef duruma göre animasyon

AnimatedContent composable, hedef duruma göre değişiklik gösterirken içeriğini canlandırır.

Row {
    var count by remember { mutableStateOf(0) }
    Button(onClick = { count++ }) {
        Text("Add")
    }
    AnimatedContent(targetState = count) { targetCount ->
        // Make sure to use `targetCount`, not `count`.
        Text(text = "Count: $targetCount")
    }
}

Her zaman lambda parametresini kullanmanız ve içeriğe yansıtmanız gerektiğini unutmayın. API bu değeri, gösterilmekte olan içeriği tanımlamak için anahtar olarak kullanır.

Varsayılan olarak, ilk içerik şeffaflaştırılır, ardından hedef içerik belirir (bu davranışa şeffaflaşma adı verilir). transitionSpec parametresine bir ContentTransform nesnesi belirterek bu animasyon davranışını özelleştirebilirsiniz. with infix işlevini kullanarak, EnterTransition ile ExitTransition değerlerini birleştirerek ContentTransform oluşturabilirsiniz. SizeTransform özelliğini using infix işlevine ekleyerek ContentTransform öğesine uygulayabilirsiniz.

AnimatedContent(
    targetState = count,
    transitionSpec = {
        // Compare the incoming number with the previous number.
        if (targetState > initialState) {
            // If the target number is larger, it slides up and fades in
            // while the initial (smaller) number slides up and fades out.
            slideInVertically { height -> height } + fadeIn() with
                slideOutVertically { height -> -height } + fadeOut()
        } else {
            // If the target number is smaller, it slides down and fades in
            // while the initial number slides down and fades out.
            slideInVertically { height -> -height } + fadeIn() with
                slideOutVertically { height -> height } + fadeOut()
        }.using(
            // Disable clipping since the faded slide-in/out should
            // be displayed out of bounds.
            SizeTransform(clip = false)
        )
    }
) { targetCount ->
    Text(text = "$targetCount")
}

EnterTransition hedef içeriğin nasıl görünmesi gerektiğini, ExitTransition ise ilk içeriğin nasıl görünmesi gerektiğini tanımlar. AnimatedVisibility için kullanılabilen tüm EnterTransition ve ExitTransition işlevlerine ek olarak AnimatedContent, slideIntoContainer ve slideOutOfContainer özelliklerini de sunar. Bunlar, slayt mesafesini başlangıç içeriğinin boyutlarına ve AnimatedContent içeriğinin hedef içeriğine göre hesaplayan slideInHorizontally/Vertically ve slideOutHorizontally/Vertically için kullanışlı alternatiflerdir.

SizeTransform, boyutun başlangıç içeriği ve hedef içerikler arasında nasıl animasyonunun gerektiğini tanımlar. Animasyonu oluştururken hem başlangıç boyutuna hem de hedef boyuta erişebilirsiniz. SizeTransform, içeriğin animasyonlar sırasında bileşen boyutuna göre kırpılıp kırpılmayacağını da kontrol eder.

var expanded by remember { mutableStateOf(false) }
Surface(
    color = MaterialTheme.colorScheme.primary,
    onClick = { expanded = !expanded }
) {
    AnimatedContent(
        targetState = expanded,
        transitionSpec = {
            fadeIn(animationSpec = tween(150, 150)) with
                fadeOut(animationSpec = tween(150)) using
                SizeTransform { initialSize, targetSize ->
                    if (targetState) {
                        keyframes {
                            // Expand horizontally first.
                            IntSize(targetSize.width, initialSize.height) at 150
                            durationMillis = 300
                        }
                    } else {
                        keyframes {
                            // Shrink vertically first.
                            IntSize(initialSize.width, targetSize.height) at 150
                            durationMillis = 300
                        }
                    }
                }
        }
    ) { targetExpanded ->
        if (targetExpanded) {
            Expanded()
        } else {
            ContentIcon()
        }
    }
}

Alt giriş ve çıkış geçişlerini canlandır

AnimatedVisibility öğesinde olduğu gibi animateEnterExit değiştiricisi de AnimatedContent içeriğinin lambdasının içinde bulunur. Doğrudan veya dolaylı alt öğelerin her birine ayrı ayrı EnterAnimation ve ExitAnimation uygulamak için bunu kullanın.

Özel animasyon ekle

AnimatedVisibility alanında olduğu gibi, transition alanı da AnimatedContent içerik lambdasının içinde bulunur. AnimatedContent geçişiyle eş zamanlı olarak çalışan özel bir animasyon efekti oluşturmak için bunu kullanın. Ayrıntılar için updateTransition bölümüne bakın.

Crossfade ile iki düzen arasında animasyon uygulayın

Crossfade, çapraz geçiş animasyonu ile iki düzen arasında animasyon yapar. current parametresine geçirilen değer değiştirildiğinde içerik, çapraz geçiş animasyonuyla değiştirilir.

var currentPage by remember { mutableStateOf("A") }
Crossfade(targetState = currentPage) { screen ->
    when (screen) {
        "A" -> Text("Page A")
        "B" -> Text("Page B")
    }
}

Yerleşik animasyon değiştiricileri

animateContentSize ile composable boyut değişikliklerine animasyon ekleme

Boyutunun yumuşak bir şekilde değiştiğini gösteren yeşil composable.
Şekil 2. Küçük ve büyük boyutlar arasında sorunsuz şekilde animasyon oluşturulabilir

animateContentSize değiştiricisi, boyut değişikliğini canlandırır.

var expanded by remember { mutableStateOf(false) }
Box(
    modifier = Modifier
        .background(colorBlue)
        .animateContentSize()
        .height(if (expanded) 400.dp else 200.dp)
        .fillMaxWidth()
        .clickable(
            interactionSource = remember { MutableInteractionSource() },
            indication = null
        ) {
            expanded = !expanded
        }

) {
}

Liste öğesi animasyonları

Bir geç liste veya ızgarada öğelerin yeniden sıralanmasına animasyon eklemek istiyorsanız Geç düzen öğesi animasyonu dokümanlarına göz atın.