Animasyon değiştiricileri ve kompozit öğeleri

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

Yerleşik animasyonlu bileşenler

AnimatedVisibility ile öğelerin görünmesini ve kaybolmasını animasyonlu hale getirme

Kendisini gösteren ve gizleyen yeşil bir bileşimli öğe
Şekil 1. Bir sütundaki öğenin görünmesini ve kaybolmasını animasyonlu hale getirme

AnimatedVisibility bileşeni, içeriğinin görünmesini ve kaybolmasını animasyonlu olarak 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 yavaşça belirip genişler ve yavaşça kaybolup küçülür. Geçiş, EnterTransition ve ExitTransition değerlerini belirterek ö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. Her nesne, davranışını özelleştirmek için isteğe bağlı parametreler kabul eder. Daha fazla bilgi için referanslara bakın.

EnterTransition ve ExitTransition örnekleri

EnterTransition ExitTransition
fadeIn
animasyonla görünürlük artırma
fadeOut
kaybolma animasyonu
slideIn
kaydırarak girme animasyonu
slideOut
kaydırarak açma animasyonu
slideInHorizontally
yatay kaydırma animasyonu
slideOutHorizontally
yatay kaydırma animasyonu
slideInVertically
dikey olarak kaydırarak animasyon
slideOutVertically
dikey kaydırma animasyonu
scaleIn
ölçeklendirme animasyonu
scaleOut
ölçeği genişletme animasyonu
expandIn
animasyonla genişlet
shrinkOut
küçültme animasyonu
expandHorizontally
yatay olarak genişlet animasyonu
shrinkHorizontally
yatay olarak küçültme animasyonu
expandVertically
dikey olarak genişlet animasyonu
shrinkVertically
dikey olarak küçültme animasyonu

AnimatedVisibility, MutableTransitionState alan bir varyant da sunar. Bu sayede, AnimatedVisibility kompozisyon ağacına eklenir eklenmez bir 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 kompozitinde belirtilen animasyonlarla alt öğenin kendi giriş ve çıkış animasyonlarının bir birleşimidir.

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ı kullanabilmesi için AnimatedVisibility'nin hiç animasyon uygulamamasını isteyebilirsiniz. Bunu yapmak için AnimatedVisibility bileşeninde EnterTransition.None ve ExitTransition.None değerlerini belirtin.

Özel animasyon ekleme

Yerleşik giriş ve çıkış animasyonları dışında özel animasyon efektleri eklemek istiyorsanız AnimatedVisibility için içerik lambdası 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 aynı anda çalışır. AnimatedVisibility, içeriğini kaldırmadan önce Transition'taki tüm animasyonların tamamlanmasını bekler. Transition'ten bağımsız olarak oluşturulan çıkış animasyonları (animate*AsState kullanımı gibi) AnimatedVisibility tarafından hesaba katılmaz ve bu nedenle, derlenebilir içerikler bitmeden kaldırılabilir.

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 işlevine bakın.

AnimatedContent ile hedef duruma göre animasyon oluşturma

AnimatedContent bileşeni, hedef duruma göre değişen içeriğini animasyonlu olarak 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 kaybolur ve ardından hedef içerik görünür hale gelir (bu davranışa kaybolma denir). transitionSpec parametresine bir ContentTransform nesnesi belirterek bu animasyon davranışını özelleştirebilirsiniz. with iç ayrımlı işlevini kullanarak EnterTransition ile ExitTransition öğelerini birleştirerek ContentTransform oluşturabilirsiniz. using iç dizili işleviyle SizeTransform değerini ContentTransform değerine 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 işlevlerini de sunar. Bunlar, slideInHorizontally/Vertically ve slideOutHorizontally/Vertically'ye uygun alternatiflerdir. Bu işlevler, slayt mesafesini AnimatedContent içeriğinin ilk içeriğin ve hedef içeriğin boyutlarına göre hesaplar.

SizeTransform, boyutun başlangıç ve hedef içerikler arasında nasıl animasyonlu olarak değişeceğini tanımlar. Animasyonu oluştururken hem ilk boyuta 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()
        }
    }
}

Çocuğun giriş ve çıkış geçişlerini animasyonlu hale getirme

AnimatedVisibility gibi animateEnterExit değiştirici de AnimatedContent içeriği lambdası içinde kullanılabilir. Doğrudan veya dolaylı alt öğelerin her birine EnterAnimation ve ExitAnimation'yi ayrı ayrı uygulamak için bunu kullanın.

Özel animasyon ekleme

AnimatedVisibility gibi transition alanı da AnimatedContent içeriği lambda'sında kullanılabilir. AnimatedContent geçişiyle aynı anda çalışan özel bir animasyon efekti oluşturmak için bunu kullanın. Ayrıntılar için updateTransition işlevine bakın.

Crossfade ile iki düzen arasında animasyonlu geçiş yapma

Crossfade, iki düzen arasında geçişi yumuşak geçiş animasyonuyla yapar. current parametresine iletilen değer değiştirilerek içerik, 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 birleştirilebilir boyut değişikliklerini canlandırma

Boyutunu sorunsuz bir şekilde değiştiren yeşil bir kompozisyon.
Şekil 2. Küçük ve daha büyük bir boyut arasında sorunsuz bir şekilde animasyonlu olarak derlenebilir

animateContentSize değiştirici, boyut değişikliğini animasyonlu olarak 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ı

Eşsiz bir liste veya ızgaradaki öğelerin yeniden sıralamasını animasyonlu olarak göstermek istiyorsanız Eşsiz düzen öğesi animasyonu dokümanlarına göz atın.