Animasyon değiştiricileri ve kompozit öğeleri

Compose, animasyonların yaygın kullanım alanlarını yönetmek için yerleşik composable'lar ve değiştiriciler içerir.

Yerleşik animasyonlu bileşenler

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

Kendisini gizleyen yeşil composable
Şekil 1. Bir sütundaki bir öğenin görünümünü ve kaybolmasını canlandırma

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
    // ...
}

Varsayılan olarak içerik soluklaşıp genişler, kaybolarak kaybolur. 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 + operatörüyle birleştirebilirsiniz. Her bir nesne, 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

GirişGeçişi 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 olarak dışarı kaydırma animasyonu
slideInVertically
dikey olarak kaydırarak animasyon
slideOutVertically
dikey olarak kaydırma animasyonu
scaleIn
ölçeklendirme animasyonu
scaleOut
ölçeği genişletme animasyonu
expandIn
animasyonda genişlet
shrinkOut
küçültme animasyonu
expandHorizontally
yatay olarak genişlet animasyonu
shrinkHorizontally
yatay küçültme animasyonu
expandVertically
dikey olarak genişlet animasyonu
shrinkVertically
dikey olarak küçültme animasyonu

AnimatedVisibility, MutableTransitionState alan bir varyant da sunuyor. 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 bileşiğinde 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 elde etmek için AnimatedVisibility composable'da EnterTransition.None ve ExitTransition.None değerlerini belirtin.

Özel animasyon ekle

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ılamaz. 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")
    }
}

Her zaman lambda parametresini kullanmanız ve içeriğe yansıtmanız gerektiğini unutmayın. API, 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ünmesi gerektiğini, ExitTransition ise ilk içeriğin nasıl yok olması gerektiğini 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'e 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, başlangıç ile hedef içerikler arasında boyut animasyonunun nasıl olması gerektiğ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 öğesinin içerik lambda'sında bulunur. Doğrudan veya dolaylı alt öğelerin her birine ayrı ayrı EnterAnimation ve ExitAnimation 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 çapraz geçiş animasyonuyla canlanıyor. current parametresine iletilen değer değiştirilerek içerik, bir 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

Yeşil composable, boyut değişimine sorunsuz şekilde dokunuyor.
Ş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 öğe animasyonu dokümanlarına göz atın.