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 composable'lar

AnimatedVisibility ile görünüşü ve kaybolma anını canlandırın

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

AnimatedVisibility composable, içeriğinin görünümüne ve ortadan kalkmasına animasyon ekler.

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 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 bir nesne, 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

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

AnimatedVisibility, MutableTransitionState alan bir varyant da sunuyor. Böylece, AnimatedVisibility beste ağacına eklenir ekz animasyon tetiklemenize olanak sağlar. 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 için giriş ve çıkış animasyonu

AnimatedVisibility içindeki içerikler (doğrudan veya dolaylı alt çocuklar), her biri için farklı animasyon davranışları belirtmek üzere animateEnterExit değiştiriciyi kullanabilir. Bu alt öğelerin her biri için görsel efekt, AnimatedVisibility composable'da belirtilen animasyonlar ile alt yayıncının 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, animateEnterExit tarihine kadar çocukların her birinin kendi animasyonlarına sahip olabilmesi için AnimatedVisibility öğesine 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ının ötesinde özel animasyon efektleri eklemek istiyorsanız AnimatedVisibility için içerik lambdasının içindeki transition özelliğini kullanarak temel Transition örneğine erişin. Geçiş örneğine eklenen tüm animasyon durumları, AnimatedVisibility giriş ve çıkış animasyonlarıyla eş zamanlı olarak çalışır. AnimatedVisibility, içeriğini kaldırmadan önce Transition içindeki tüm animasyonların bitmesini bekler. Transition bağımsız değişkeninden bağımsız olarak oluşturulan (animate*AsState kullanma gibi) çıkış animasyonlarında AnimatedVisibility bunları hesaba katamaz ve dolayısıyla composable içeriği bitmeden önce 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 sayfasına bakın.

AnimatedContent ile hedef duruma göre animasyon uygula

AnimatedContent composable, hedef duruma göre değişen içeriklerine animasyon uygular.

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, gösterilen içeriği tanımlamak için bu değeri anahtar olarak kullanır.

Varsayılan olarak ilk içerik yavaşça kaybolur ve daha sonra hedef içerik yavaşça kaybolur (bu davranışa fare arasından geçiş denir). transitionSpec parametresi için bir ContentTransform nesnesi belirterek bu animasyon davranışını özelleştirebilirsiniz. with infix işlevini kullanarak EnterTransition öğesini bir ExitTransition ile birleştirerek ContentTransform oluşturabilirsiniz. SizeTransform öğesini using infix işleviyle 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 yok olması gerektiğini tanımlar. AnimatedContent, AnimatedVisibility için kullanılabilen tüm EnterTransition ve ExitTransition işlevlerinin yanı sıra slideIntoContainer ve slideOutOfContainer özelliklerini de sunar. Bunlar, slayt mesafesini ilk içeriğin boyutlarına ve AnimatedContent içeriğinin hedef içeriğine dayanarak hesaplayan slideInHorizontally/Vertically ve slideOutHorizontally/Vertically için kullanışlı alternatiflerdir.

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, içeriğin animasyonlar sırasında 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)) 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ırma

AnimatedVisibility gibi, animateEnterExit değiştirici de AnimatedContent öğesinin içerik lambda'sında bulunur. Doğrudan veya dolaylı çocukların her birine EnterAnimation ve ExitAnimation özelliklerini ayrı ayrı uygulamak için bunu kullanın.

Özel animasyon ekle

AnimatedVisibility gibi, transition alanı da AnimatedContent öğesinin içerik lambdası içinde kullanılabilir. AnimatedContent geçişiyle eş zamanlı olarak çalışan bir özel animasyon efekti oluşturmak için bunu kullanın. Ayrıntılar için updateTransition sayfasına bakın.

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

Crossfade, iki düzen arasında çapraz geçiş animasyonuyla canlanıyor. current parametresine iletilen değer açılıp kapatıldığında içerik, geçiş animasyonu ile 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şikliklerini canlandırın

Yeşil composable, boyut değişimine sorunsuz şekilde dokunuyor.
Şekil 2. Küçük ve büyük boyutlar arasında sorunsuz animasyonlar oluşturma

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ı

Tembel liste veya ızgara içindeki öğe yeniden sıralamalarına animasyon eklemek istiyorsanız Geç düzen öğesi animasyonu dokümanlarına göz atın.