Animasyon değiştiricileri ve kompozit öğeleri

Compose, yaygın animasyon kullanım alanlarını işlemek için yerleşik composable'lar ve değiştiricilerle birlikte gelir.

Yerleşik animasyonlu composable'lar

AnimatedVisibility ile görünme ve kaybolma animasyonu oluşturma

Yeşil composable'ın gösterilmesi ve gizlenmesi
1. şekil. Bir sütundaki öğenin görünme ve kaybolma animasyonunu yapma

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

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 solarak 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 + operatörüyle birleştirebilirsiniz. Her biri, davranışını özelleştirmek için isteğe bağlı parametreleri kabul eder. Daha fazla bilgi için referanslara bakın.

EnterTransition ve ExitTransition örnekleri

EnterTransition ExitTransition
fadeIn
fade in animation
fadeOut
solarak kaybolma animasyonu
slideIn
kaydırma animasyonu
slideOut
kayarak çıkma animasyonu
slideInHorizontally
Yatay kaydırma animasyonu
slideOutHorizontally
yatay kaydırma animasyonu
slideInVertically
Dikey kaydırma animasyonu
slideOutVertically
dikey olarak kaydırarak çıkarma animasyonu
scaleIn
ölçeklendirme animasyonu
scaleOut
ölçeği genişletme animasyonu
expandIn
animasyonla genişletme
shrinkOut
küçülerek kaybolma animasyonu
expandHorizontally
yatay genişletme animasyonu
shrinkHorizontally
yatay olarak küçültme animasyonu
expandVertically
dikey olarak genişletme animasyonu
shrinkVertically
dikey olarak küçültme animasyonu

AnimatedVisibility, MutableTransitionState. Bu sayede, AnimatedVisibility kompozisyon ağacına eklendiği anda animasyonu tetikleyebilirsiniz. Animasyon durumunu gözlemlemek için de kullanışlı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 için giriş ve çıkış animasyonları

AnimatedVisibility içindeki içerikler (doğrudan veya dolaylı alt öğeler), her biri için farklı animasyon davranışı belirtmek üzere animateEnterExit değiştiricisini kullanabilir. Bu alt öğelerin her birinin görsel efekti, AnimatedVisibility composable'da belirtilen animasyonların ve alt öğenin kendi giriş ve çıkış animasyonlarının bir 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 ile kendi animasyonlarını oluşturabilmeleri için AnimatedVisibility'nın hiç animasyon uygulamamasını isteyebilirsiniz. Bunu yapmak için EnterTransition.None ve ExitTransition.None değerlerini AnimatedVisibility composable'ında belirtin.

Özel animasyon ekleme

Yerleşik giriş ve çıkış animasyonlarının ötesinde özel animasyon efektleri eklemek istiyorsanız Transition örneğine AnimatedVisibility için içerik lambda'sındaki transition özelliği üzerinden erişin. Geçiş örneğine eklenen tüm animasyon durumları, AnimatedVisibility öğesinin giriş ve çıkış animasyonlarıyla aynı anda çalışır. AnimatedVisibility, içeriğini kaldırmadan önce Transition içindeki tüm animasyonların tamamlanmasını bekler. Transition'dan bağımsız olarak oluşturulan çıkış animasyonları (ör. Transition kullanılarak) için AnimatedVisibility bunları hesaba katamaz ve bu nedenle, bitmeden önce birleştirilebilir içeriği kaldırabilir.animate*AsState

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 başlıklı makaleyi inceleyin.

AnimatedContent ile hedef duruma göre animasyon oluşturma

AnimatedContent composable, hedef duruma göre değişirken içeriğini animasyonla gösterir.

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

Lambda parametresini her zaman kullanmanız ve içeriğe yansıtmanız gerektiğini unutmayın. API, şu anda gösterilen içeriği tanımlamak için bu değeri anahtar olarak kullanır.

Varsayılan olarak, ilk içerik silinir ve ardından hedef içerik görünür (bu davranışa geçişli silme adı verilir). transitionSpec parametresine bir ContentTransform nesnesi belirterek bu animasyon davranışını özelleştirebilirsiniz. ContentTransform oluşturmak için with infix işlevini kullanarak EnterTransition ile ExitTransition öğesini birleştirebilirsiniz. SizeTransform ContentTransform'e using infix işleviyle ekleyerek 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() togetherWith
                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() togetherWith
                slideOutVertically { height -> height } + fadeOut()
        }.using(
            // Disable clipping since the faded slide-in/out should
            // be displayed out of bounds.
            SizeTransform(clip = false)
        )
    }, label = "animated content"
) { targetCount ->
    Text(text = "$targetCount")
}

EnterTransition, hedef içeriğin nasıl görüneceğini, ExitTransition ise ilk içeriğin nasıl kaybolacağını tanımlar. AnimatedVisibility için kullanılabilen tüm EnterTransition ve ExitTransition işlevlerine ek olarak AnimatedContent, slideIntoContainer ve slideOutOfContainer özelliklerini sunar. Bunlar, slideInHorizontally/Vertically ve slideOutHorizontally/Vertically için uygun alternatiflerdir. AnimatedContent içeriğinin ilk içeriğinin ve hedef içeriğinin boyutlarına göre kaydırma mesafesini hesaplar.

SizeTransform, boyutun ilk ve hedef içerikler arasında nasıl animasyonlu hale getirileceğini tanımlar. Animasyonu oluştururken hem başlangıç boyutuna hem de hedef boyuta erişebilirsiniz. SizeTransform, animasyonlar sırasında içeriğin bileşen boyutuna 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)) togetherWith
                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
                        }
                    }
                }
        }, label = "size transform"
    ) { targetExpanded ->
        if (targetExpanded) {
            Expanded()
        } else {
            ContentIcon()
        }
    }
}

Alt öğelerin giriş ve çıkış geçişlerine animasyon ekleme

AnimatedVisibility gibi, animateEnterExit değiştiricisi de AnimatedContent öğesinin içerik lambda'sında kullanılabilir. EnterAnimation ve ExitAnimation öğelerini doğrudan veya dolaylı alt öğelerin her birine ayrı ayrı uygulamak için bu yöntemi kullanın.

Özel animasyon ekleme

AnimatedVisibility gibi, transition alanı da AnimatedContent öğesinin içerik lambda'sında kullanılabilir. Bunu, AnimatedContent geçişiyle aynı anda çalışan özel bir animasyon efekti oluşturmak için kullanın. Ayrıntılar için updateTransition bölümüne bakın.

Crossfade ile iki düzen arasında animasyon oluşturma

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

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

Yerleşik animasyon değiştiriciler

animateContentSize ile composable boyut değişikliklerini canlandırma

Boyut değişikliğini sorunsuz bir şekilde animasyonla gösteren yeşil renkli composable.
Şekil 2. Küçük ve büyük boyut arasında sorunsuz bir şekilde animasyon oluşturan composable'lar

animateContentSize değiştiricisi, boyut değişikliğini animasyonla gösterir.

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ı

Lazy list veya Lazy grid içindeki öğelerin yeniden sıralanmasını animasyonlu hale getirmek istiyorsanız Lazy layout item animation dokümanlarına göz atın.