Animasyon değiştiricileri ve kompozit öğeleri

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

Yerleşik animasyonlu composable'lar

Compose, içeriğin görünümünü, kaybolmasını ve düzen değişikliklerini canlandıran çeşitli composable'lar sunar.

Görünme ve kaybolma animasyonu

Yeşil renkli bir composable gösterilip gizleniyor.
Şekil 1. Sütundaki bir öğenin görünme ve kaybolma animasyonu.

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

Varsayılan olarak içerik, belirerek ve genişleyerek görünür, kaybolarak ve küçülerek kaybolur. EnterTransition ve ExitTransition nesnelerini belirterek bu geçişi özelleştirin.

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)
    )
}

Önceki örnekte gösterildiği gibi, birden fazla EnterTransition veya ExitTransition nesnesini + operatörüyle birleştirebilirsiniz. Bu nesnelerin her biri, davranışını özelleştirmek için isteğe bağlı parametreleri kabul eder. Daha fazla bilgi için referans sayfalarına bakın.

Giriş ve çıkış geçişi örnekleri

EnterTransition ExitTransition
fadeIn
Kullanıcı arayüzü öğesi kademeli olarak görünür hale gelir.
fadeOut
Bir kullanıcı arayüzü öğesi kademeli olarak görünümden kaybolur.
slideIn
Bir kullanıcı arayüzü öğesi, ekran dışından kayarak görünür hale gelir.
slideOut
Bir kullanıcı arayüzü öğesi kayarak ekranın dışına çıkıyor.
slideInHorizontally
Kullanıcı arayüzü öğesi, yatay olarak kayarak görünüme girer.
slideOutHorizontally
Kullanıcı arayüzü öğesi, yatay olarak kayarak görünümden çıkar.
slideInVertically
Bir kullanıcı arayüzü öğesi dikey olarak kayarak görünüme girer.
slideOutVertically
Kullanıcı arayüzü öğesi dikey olarak kayarak görünümden çıkar.
scaleIn
Bir kullanıcı arayüzü öğesi büyüyerek görünür hale geliyor.
scaleOut
Bir kullanıcı arayüzü öğesi küçülür ve görünümden çıkar.
expandIn
Kullanıcı arayüzü öğesi, merkezi bir noktadan genişleyerek görünür hale gelir.
shrinkOut
Kullanıcı arayüzü öğesi küçülerek merkezi bir noktaya doğru kaybolur.
expandHorizontally
Bir kullanıcı arayüzü öğesi yatay olarak genişleyerek görünür hale gelir.
shrinkHorizontally
Kullanıcı arayüzü öğesi yatay olarak küçülerek görünümden kaybolur.
expandVertically
Kullanıcı arayüzü öğesi dikey olarak genişleyerek görünür hale gelir.
shrinkVertically
Kullanıcı arayüzü öğesi dikey olarak küçülerek görünümden çıkar.

AnimatedVisibility, MutableTransitionState bağımsız değişkeni alan bir varyant da sunar. Bu sayede, AnimatedVisibility composable oluşturma 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"
        }
    )
}

Alt öğeler için giriş ve çıkış animasyonu ekleme

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 ile alt öğenin kendi giriş ve çıkış animasyonlarının 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, AnimatedVisibility öğesinin hiç animasyon uygulamamasını isteyebilirsiniz. Böylece çocuklar, animateEnterExit ile kendi animasyonlarını oluşturabilir. Bunu yapmak için AnimatedVisibility composable'ında EnterTransition.None ve ExitTransition.None değerlerini belirtin.

Özel animasyon ekleme

Yerleşik giriş ve çıkış animasyonlarının ötesinde özel animasyon efektleri eklemek istiyorsanız AnimatedVisibility için içerik lambda'sındaki transition özelliğini kullanarak 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 içindeki tüm animasyonların tamamlanmasını bekler. Transition dışında oluşturulan çıkış animasyonları (ör. animate*AsState kullanılarak oluşturulanlar) AnimatedVisibility tarafından hesaba katılamaz. Bu nedenle, içerik composable tamamlanmadan 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)
    )
}

Animasyonları yönetmek için Transition kullanma hakkında daha fazla bilgi edinmek istiyorsanız Geçişle birden fazla özelliği aynı anda canlandırma başlıklı makaleyi inceleyin.

Hedef duruma göre animasyon oluşturma

AnimatedContent composable, 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")
    }
}

Varsayılan olarak, ilk içerik yavaşça kaybolur ve ardından hedef içerik yavaşça görünür (bu davranışa karartma denir). transitionSpec parametresine bir ContentTransform nesnesi belirterek bu animasyon davranışını özelleştirebilirsiniz. with infix işlevini kullanarak bir EnterTransition nesnesini ExitTransition nesnesiyle birleştirerek ContentTransform örneği oluşturabilirsiniz. using infix işleviyle ekleyerek ContentTransform nesnesine SizeTransform 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 tanımlar ve ExitTransition, ilk içeriğin nasıl kaybolması gerektiğini tanımlar. AnimatedVisibility için kullanılabilen tüm EnterTransition ve ExitTransition işlevlerine ek olarak AnimatedContent, slideIntoContainer ve slideOutOfContainer işlevlerini sunar. Bunlar, AnimatedContent içeriğinin ilk içeriğinin ve hedef içeriğinin boyutlarına göre kaydırma mesafesini hesaplayan slideInHorizontally/Vertically ve slideOutHorizontally/Vertically için kullanışlı alternatiflerdir.

SizeTransform, boyutun ilk ve hedef içerikler arasında nasıl animasyonlu hale getirileceğ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 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)) 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 öğe giriş ve çıkış geçişlerine animasyon ekleme

AnimatedVisibility gibi animateEnterExit değiştirici de AnimatedContent öğesinin içerik lambda'sında kullanılabilir. EnterAnimation ve ExitAnimation değerlerini doğrudan veya dolaylı alt öğelerin her birine ayrı ayrı uygulamak için bunu kullanın.

Özel animasyon ekleme

AnimatedVisibility gibi transition alanı da AnimatedContent öğesinin içerik 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 bölümüne bakın.

İki düzen arasında animasyon oluşturma

Crossfade, iki düzen arasında geçiş animasyonuyla animasyon oluşturur. current parametresine iletilen değeri değiştirerek 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

Compose, doğrudan composable'lar üzerinde belirli değişiklikleri canlandırmak için değiştiriciler sağlar.

Oluşturulabilir boyut değişikliklerini canlandırma

Boyut değişikliğini sorunsuz bir şekilde canlandıran yeşil composable.
Şekil 2. Küçük ve büyük boyut arasında sorunsuz bir şekilde animasyon oluşturan Composable

animateContentSize değiştiricisi, boyut değişikliğini animasyonlu hale getirir.

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 listesi veya ızgarasındaki öğe yeniden sıralamalarını animasyonlu hale getirmek istiyorsanız Lazy düzen öğesi animasyonu belgelerine göz atın.