Oluşturma'daki Animasyonlar için hızlı rehber

Oluşturma, birçok yerleşik animasyon mekanizmasına sahiptir ve bir araç oluşturmayı, hangisini seçeceğinizi bilmeniz gerekir. Aşağıda, animasyonların yaygın kullanım alanlarının bir listesi yer almaktadır. Örneğin, kullanıma sunulan farklı API seçeneklerinin tümü hakkında daha ayrıntılı bilgi Animasyon Oluşturma dokümanlarının tamamını okuyun.

Ortak composable özelliklerini canlandırma

Compose, birçok yaygın sorun için çözüm bulmanıza olanak tanıyan kullanışlı API'ler sunar. kullanım alanlarına yönlendirebilirsiniz. Bu bölümde, yaygın olarak kullanılan özellikleri ele alacağız.

Görünen / kaybolan animasyon

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

Bir Besteci'yi gizlemek veya göstermek için AnimatedVisibility simgesini kullanın. İçerideki çocuklar AnimatedVisibility, kendi girişimi için Modifier.animateEnterExit() kullanabilir tıklayın veya geçişten çıkın.

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

AnimatedVisibility giriş ve çıkış parametreleri, bir composable, görünüp kaybolduğunda davranır. dokümanlarına bakın.

Bir composable'ın görünürlüğünü canlandırmanın bir başka yolu da animateFloatAsState kullanarak zaman içinde alfa sürümü:

var visible by remember {
    mutableStateOf(true)
}
val animatedAlpha by animateFloatAsState(
    targetValue = if (visible) 1.0f else 0f,
    label = "alpha"
)
Box(
    modifier = Modifier
        .size(200.dp)
        .graphicsLayer {
            alpha = animatedAlpha
        }
        .clip(RoundedCornerShape(8.dp))
        .background(colorGreen)
        .align(Alignment.TopCenter)
) {
}

Ancak alfayı değiştirmek, composable'ın kalıcı olarak yerleştirdiği alanı işgal etmeye devam eder. Bu ekran okuyucuların ve diğer erişilebilirlik mekanizmalarının ekranda görebilirsiniz. Öte yandan, AnimatedVisibility sonunda öğe bileşimden çıkarılabilir.

Bir composable'ın alfasına animasyon ekleme
Şekil 2. Bir composable'ın alfasına animasyon ekleme
'nı inceleyin.

Arka plan rengini canlandır

Renklerin birbirine dönüştüğü bir animasyon olarak zaman içinde değişen arka plan rengiyle oluşturulabilir.
Şekil 3. composable'ın arka plan rengine animasyon ekleme
'nı inceleyin.

val animatedColor by animateColorAsState(
    if (animateBackgroundColor) colorGreen else colorBlue,
    label = "color"
)
Column(
    modifier = Modifier.drawBehind {
        drawRect(animatedColor)
    }
) {
    // your composable here
}

Bu seçenek, Modifier.background() kullanımına kıyasla daha etkilidir. Modifier.background(), tek seferlik renk ayarı için kabul edilebilir, ancak canlandırması, daha fazla yeniden bestelemeye gerekir.

Arka plan rengini sonsuza kadar canlandırmak için animasyonu tekrarlama bölümüne bakın bölümünü inceleyin.

Bir composable'ın boyutunu canlandırma

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

Oluşturma, composable'ların boyutunu birkaç farklı şekilde canlandırmanızı sağlar. Tekliflerinizi otomatikleştirmek ve optimize etmek için Birleştirilebilir boyut değişiklikleri arasındaki animasyonlar için animateContentSize().

Örneğin, birden fazla boyuta genişleyebilen metin içeren bir kutunuz varsa daha yumuşak bir görüntü için Modifier.animateContentSize() kullanabilirsiniz geçiş:

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
        }

) {
}

Ayrıca, açıklama için AnimatedContent ve SizeTransform kullanabilirsiniz ve boyut değişikliklerinin nasıl yapılması gerektiğini öğreneceğiz.

Bir composable'ın konumunu canlandır

Aşağı ve sağa doğru düzgün şekilde animasyon yapan yeşil composable
Şekil 5. Ofsetle derlenebilir taşıma
'nı inceleyin.

Bir composable'ın konumunu canlandırmak için Modifier.offset{ } öğesini şununla birlikte kullanın: animateIntOffsetAsState().

var moved by remember { mutableStateOf(false) }
val pxToMove = with(LocalDensity.current) {
    100.dp.toPx().roundToInt()
}
val offset by animateIntOffsetAsState(
    targetValue = if (moved) {
        IntOffset(pxToMove, pxToMove)
    } else {
        IntOffset.Zero
    },
    label = "offset"
)

Box(
    modifier = Modifier
        .offset {
            offset
        }
        .background(colorBlue)
        .size(100.dp)
        .clickable(
            interactionSource = remember { MutableInteractionSource() },
            indication = null
        ) {
            moved = !moved
        }
)

composable'ların diğer öğelerin üzerine veya üzerine çizilmediğinden emin olmak için konumu veya boyutu canlandırmak için composable'ları Modifier.layout{ } kullanın. Bu değiştiricisi, boyut ve konum değişikliklerini üst öğeye yayar ve bu da, yardımcı olur.

Örneğin, bir Box öğesini Column ve diğer alt öğeler içinde taşıyorsanız Box hareket ettiğinde hareket etmesi gerekiyorsa, ofset bilgilerini Modifier.layout{ } şu şekildedir:

var toggled by remember {
    mutableStateOf(false)
}
val interactionSource = remember {
    MutableInteractionSource()
}
Column(
    modifier = Modifier
        .padding(16.dp)
        .fillMaxSize()
        .clickable(indication = null, interactionSource = interactionSource) {
            toggled = !toggled
        }
) {
    val offsetTarget = if (toggled) {
        IntOffset(150, 150)
    } else {
        IntOffset.Zero
    }
    val offset = animateIntOffsetAsState(
        targetValue = offsetTarget, label = "offset"
    )
    Box(
        modifier = Modifier
            .size(100.dp)
            .background(colorBlue)
    )
    Box(
        modifier = Modifier
            .layout { measurable, constraints ->
                val offsetValue = if (isLookingAhead) offsetTarget else offset.value
                val placeable = measurable.measure(constraints)
                layout(placeable.width + offsetValue.x, placeable.height + offsetValue.y) {
                    placeable.placeRelative(offsetValue)
                }
            }
            .size(100.dp)
            .background(colorGreen)
    )
    Box(
        modifier = Modifier
            .size(100.dp)
            .background(colorBlue)
    )
}

2. kutu,X, Y konumunu canlandırıyor; üçüncü kutu da Y miktarında hareket ederek yanıt veriyor.
Şekil 6. Modifier.layout{ }
ile animasyon

Bir composable'ın dolgusunu canlandırma

Yeşil composable, tıklandığında küçülüyor ve dolgu canlandırılıyor
Şekil 7. Dolgusu animasyonla oluşturulabilir
'nı inceleyin.

Bir composable'ın dolgusuna animasyon eklemek için animateDpAsState öğesini şununla birlikte kullanın: Modifier.padding():

var toggled by remember {
    mutableStateOf(false)
}
val animatedPadding by animateDpAsState(
    if (toggled) {
        0.dp
    } else {
        20.dp
    },
    label = "padding"
)
Box(
    modifier = Modifier
        .aspectRatio(1f)
        .fillMaxSize()
        .padding(animatedPadding)
        .background(Color(0xff53D9A1))
        .clickable(
            interactionSource = remember { MutableInteractionSource() },
            indication = null
        ) {
            toggled = !toggled
        }
)

Bir composable'ın yüksekliğini gösterme

Şekil 8. Composable'ın tıklamayla animasyon eklemesi

Bir composable'ın yüksekliğine animasyon eklemek için animateDpAsState öğesini Modifier.graphicsLayer{ }. Tek seferlik yükseklik değişiklikleri için Modifier.shadow() Gölgeyi animasyon haline getiriyorsanız Modifier.graphicsLayer{ } değiştiricisi daha yüksek performanslıdır.

val mutableInteractionSource = remember {
    MutableInteractionSource()
}
val pressed = mutableInteractionSource.collectIsPressedAsState()
val elevation = animateDpAsState(
    targetValue = if (pressed.value) {
        32.dp
    } else {
        8.dp
    },
    label = "elevation"
)
Box(
    modifier = Modifier
        .size(100.dp)
        .align(Alignment.Center)
        .graphicsLayer {
            this.shadowElevation = elevation.value.toPx()
        }
        .clickable(interactionSource = mutableInteractionSource, indication = null) {
        }
        .background(colorGreen)
) {
}

Alternatif olarak, Card composable'ı kullanın ve yükseklik özelliğini eyalete göre farklı değerler.

Metin ölçeğini, çevirisini veya döndürmeyi canlandırma

"Şöyle" anlamına gelen metin
Şekil 9. İki boyut arasında metin animasyonu sorunsuz
'nı inceleyin.

Metnin ölçeğini, çevirisini veya döndürülmesini canlandırırken textMotion özelliğini ayarlayın parametresini TextStyle parametresinden TextMotion.Animated olarak ayarlayın. Bu şekilde daha sorunsuz metin animasyonları arasındaki geçişleri gösterir. Modifier.graphicsLayer{ } kullanarak şu işlemleri yapabilirsiniz: çevirebilir, döndürebilir veya ölçeklendirebilirsiniz.

val infiniteTransition = rememberInfiniteTransition(label = "infinite transition")
val scale by infiniteTransition.animateFloat(
    initialValue = 1f,
    targetValue = 8f,
    animationSpec = infiniteRepeatable(tween(1000), RepeatMode.Reverse),
    label = "scale"
)
Box(modifier = Modifier.fillMaxSize()) {
    Text(
        text = "Hello",
        modifier = Modifier
            .graphicsLayer {
                scaleX = scale
                scaleY = scale
                transformOrigin = TransformOrigin.Center
            }
            .align(Alignment.Center),
        // Text composable does not take TextMotion as a parameter.
        // Provide it via style argument but make sure that we are copying from current theme
        style = LocalTextStyle.current.copy(textMotion = TextMotion.Animated)
    )
}

Metin rengini canlandır

Kelimeler
Şekil 10. Animasyonlu metin rengini gösteren örnek
'nı inceleyin.

Metin rengine animasyon eklemek için BasicText composable'da color lambda öğesini kullanın:

val infiniteTransition = rememberInfiniteTransition(label = "infinite transition")
val animatedColor by infiniteTransition.animateColor(
    initialValue = Color(0xFF60DDAD),
    targetValue = Color(0xFF4285F4),
    animationSpec = infiniteRepeatable(tween(1000), RepeatMode.Reverse),
    label = "color"
)

BasicText(
    text = "Hello Compose",
    color = {
        animatedColor
    },
    // ...
)

Farklı içerik türleri arasında geçiş yapın

"Yeşil ekran"da şöyle diyor:
Şekil 11. Farklı composable'lar arasındaki değişiklikleri canlandırmak için Animasyonlu İçeriği kullanma (yavaşlama)
'nı inceleyin.

Dilerseniz farklı composable'lar arasında animasyon oluşturmak için AnimatedContent simgesini kullanın. yalnızca composable'lar arasında standart geçiş yapmak istiyorsanız Crossfade kullanın.

var state by remember {
    mutableStateOf(UiState.Loading)
}
AnimatedContent(
    state,
    transitionSpec = {
        fadeIn(
            animationSpec = tween(3000)
        ) togetherWith fadeOut(animationSpec = tween(3000))
    },
    modifier = Modifier.clickable(
        interactionSource = remember { MutableInteractionSource() },
        indication = null
    ) {
        state = when (state) {
            UiState.Loading -> UiState.Loaded
            UiState.Loaded -> UiState.Error
            UiState.Error -> UiState.Loading
        }
    },
    label = "Animated Content"
) { targetState ->
    when (targetState) {
        UiState.Loading -> {
            LoadingScreen()
        }
        UiState.Loaded -> {
            LoadedScreen()
        }
        UiState.Error -> {
            ErrorScreen()
        }
    }
}

AnimatedContent, birçok farklı giriş türünü gösterecek şekilde özelleştirilebilir. emin olun. Daha fazla bilgi için şu adresteki dokümanları okuyun: AnimatedContent veya bu blog yayınını okuyun AnimatedContent

Farklı hedeflere giderken animasyon kullan

İki composable, biri yeşil, diğeri "Açılış", diğeri "Detay" (Detay) yazısı ve composable'ı, composable'ın üzerine kaydırarak animasyon yapıyor.
Şekil 12. Gezinme-kompozisyonu kullanarak composable'lar arasında animasyon oluşturma
'nı inceleyin.

composable'ı kullanırken iki composable arasındaki geçişlere animasyon eklemek için navigation-compose yapısını kullanmak yerine, enterTransition ve Bir composable'da exitTransition. Ayrıca, varsayılan animasyonu üst düzeydeki tüm hedefler için kullanılır NavHost:

val navController = rememberNavController()
NavHost(
    navController = navController, startDestination = "landing",
    enterTransition = { EnterTransition.None },
    exitTransition = { ExitTransition.None }
) {
    composable("landing") {
        ScreenLanding(
            // ...
        )
    }
    composable(
        "detail/{photoUrl}",
        arguments = listOf(navArgument("photoUrl") { type = NavType.StringType }),
        enterTransition = {
            fadeIn(
                animationSpec = tween(
                    300, easing = LinearEasing
                )
            ) + slideIntoContainer(
                animationSpec = tween(300, easing = EaseIn),
                towards = AnimatedContentTransitionScope.SlideDirection.Start
            )
        },
        exitTransition = {
            fadeOut(
                animationSpec = tween(
                    300, easing = LinearEasing
                )
            ) + slideOutOfContainer(
                animationSpec = tween(300, easing = EaseOut),
                towards = AnimatedContentTransitionScope.SlideDirection.End
            )
        }
    ) { backStackEntry ->
        ScreenDetails(
            // ...
        )
    }
}

Giriş ve çıkış geçişlerinin farklı türleri vardır. farklı efektleri görmek için dokümanları inceleyin.

Animasyonu tekrarlama

İki renk arasında animasyonla sürekli olarak mavi bir arka plana dönüşen yeşil bir arka plan.
Şekil 13. İki değer arasında sonsuza kadar animasyonlu arka plan rengi
'nı inceleyin.

rememberInfiniteTransition öğesini bir infiniteRepeatable ile kullanın Animasyonunuzu sürekli olarak tekrarlamak için animationSpec tuşuna basın. RepeatModes kelimesini şununla değiştirin: ne yapmanız gerektiğini belirtmelisiniz.

Belirli sayıda tekrarlamak için finiteRepeatable öğesini kullanın.

val infiniteTransition = rememberInfiniteTransition(label = "infinite")
val color by infiniteTransition.animateColor(
    initialValue = Color.Green,
    targetValue = Color.Blue,
    animationSpec = infiniteRepeatable(
        animation = tween(1000, easing = LinearEasing),
        repeatMode = RepeatMode.Reverse
    ),
    label = "color"
)
Column(
    modifier = Modifier.drawBehind {
        drawRect(color)
    }
) {
    // your composable here
}

Bir composable başlatıldığında animasyon başlat

LaunchedEffect, besteye bir composable girdiğinde çalışır. Başlıyor bir composable'ın lansmanında gösterilen animasyon durum değişikliği. Şunu başlatmak için animateTo yöntemiyle Animatable kullanılıyor: başlatma animasyonu:

val alphaAnimation = remember {
    Animatable(0f)
}
LaunchedEffect(Unit) {
    alphaAnimation.animateTo(1f)
}
Box(
    modifier = Modifier.graphicsLayer {
        alpha = alphaAnimation.value
    }
)

Sıralı animasyonlar oluşturma

Birbirinin arasında yeşil okların olduğu ve birbiri ardına hareket eden dört daire.
Şekil 14. Sıralı animasyonun tek tek nasıl ilerlediğini gösteren şema.

Sıralı veya eşzamanlı gerçekleştirmek için Animatable eş zamanlı API'lerini kullanın animasyonları da ekler. Diğer nedenlerin ardından Animatable numaralı telefondan animateTo aranıyor devam etmeden önce önceki animasyonların bitmesini beklemek için her animasyonun bitmesini bekleyin . Bunun nedeni, bunun bir askıya alma işlevi olmasıdır.

val alphaAnimation = remember { Animatable(0f) }
val yAnimation = remember { Animatable(0f) }

LaunchedEffect("animationKey") {
    alphaAnimation.animateTo(1f)
    yAnimation.animateTo(100f)
    yAnimation.animateTo(500f, animationSpec = tween(100))
}

Eşzamanlı animasyonlar oluşturma

Yeşil okların olduğu ve hepsi aynı anda canlandıran üç daire.
Şekil 15. Eşzamanlı animasyonların aynı anda nasıl ilerlediğini gösteren şema.

Eş yordam API'leri (Animatable#animateTo() veya animate) kullanın veya Transition API'sini kullanın. Birden fazla fonksiyonları eş yordamda başlattığında, animasyonları da zaman:

val alphaAnimation = remember { Animatable(0f) }
val yAnimation = remember { Animatable(0f) }

LaunchedEffect("animationKey") {
    launch {
        alphaAnimation.animateTo(1f)
    }
    launch {
        yAnimation.animateTo(100f)
    }
}
.

Drive için aynı durumu kullanmak istiyorsanız updateTransition API'yi kullanabilirsiniz. birçok farklı özellik animasyonu oluşturabilirsiniz. Aşağıdaki örnekte, durum değişikliğiyle kontrol edilen iki mülk (rect ve borderWidth):

var currentState by remember { mutableStateOf(BoxState.Collapsed) }
val transition = updateTransition(currentState, label = "transition")

val rect by transition.animateRect(label = "rect") { state ->
    when (state) {
        BoxState.Collapsed -> Rect(0f, 0f, 100f, 100f)
        BoxState.Expanded -> Rect(100f, 100f, 300f, 300f)
    }
}
val borderWidth by transition.animateDp(label = "borderWidth") { state ->
    when (state) {
        BoxState.Collapsed -> 1.dp
        BoxState.Expanded -> 0.dp
    }
}

Animasyon performansını optimize et

Compose'daki animasyonlar performans sorunlarına neden olabilir. Bunun nedeni, Örneğin, ekrandaki pikselleri hızlıca taşımak veya değiştirmek, her kare kare resim kullanabilirsiniz.

İçerik oluşturmanın farklı aşamalarını göz önünde bulundurun: kompozisyon, düzen ve çizim. Eğer animasyonunuz düzen aşamasını değiştiriyorsa, etkilenen tüm composable'ların tekrar çizebilirsiniz. Animasyonunuz çizim aşamasında gerçekleşiyorsa, animasyon düzeninde çalıştırmaya kıyasla daha yüksek performanslı olacaktır. çünkü bu, genel olarak daha az işin olacağı anlamına gelir.

Uygulamanızın animasyon sırasında mümkün olduğunca az işlem yapmasını sağlamak için lambda'yı seçin sürümünü kullanın.Modifier Bu işlem, yeniden besteyi atlar ve bu içeriği besteleme aşamasının dışında bırakan Bu değiştirici her zaman çizimde çalıştığı için Modifier.graphicsLayer{ } aşamasındayız. Bu konu hakkında daha fazla bilgi için okuma işlemlerini erteleme bölümüne performans belgelerini inceleyin.

Animasyon zamanlamasını değiştirme

Oluşturma işleminde varsayılan olarak, çoğu animasyon için yay animasyonları kullanılır. Yaylar fizik tabanlı animasyonlar daha doğal görünür. Ayrıca bu öğeler, sabit bir süre yerine nesnenin o anki hızı dikkate alınır. Varsayılanı geçersiz kılmak isterseniz yukarıda gösterilen tüm animasyon API'leri animasyonun çalışma şeklini özelleştirmek için animationSpec ayarlayabilir, belirli bir süre boyunca devam etmesini mi yoksa daha daha hareketli mi olmasını istediğinizi seçin.

Aşağıda, farklı animationSpec seçeneklerinin özeti verilmiştir:

  • spring: Tüm animasyonlar için varsayılan olan fizik tabanlı animasyon. Siz farklı bir animasyon elde etmek için sertliği veya dampingRatio'yu değiştirebilirsiniz. görünüm ve izlenimi sağlar.
  • tween (arasında kısaltması): Süreye dayalı animasyon, animasyonlu Easing fonksiyonuna sahip iki değer arasında.
  • keyframes: Bir animasyon ekler.
  • repeatable: Belirli sayıda çalıştırılan süreye dayalı spesifikasyon. RepeatMode tarafından belirtilir.
  • infiniteRepeatable: Sonsuza kadar çalışan, süreye dayalı spesifikasyon.
  • snap: Animasyon olmadan bitiş değerine anında tutturur.
ziyaret edin.
Alternatif metninizi buraya yazın
Şekil 16. Spesifikasyon ayarlanmadı ve Özel Spring spesifikasyon grubu
'nı inceleyin.

animationSpecs hakkında daha fazla bilgi için dokümanların tamamını okuyun.

Ek kaynaklar

Compose'daki eğlenceli animasyonlarla ilgili daha fazla örnek için aşağıdakilere göz atın: