Oluşturma işleminde birçok yerleşik animasyon mekanizması bulunur ve hangisini seçeceğinizi bilmek zor olabilir. Aşağıda, animasyonun yaygın kullanım alanlarının bir listesi bulunmaktadır. Kullanabileceğiniz farklı API seçeneklerinin tamamı hakkında daha ayrıntılı bilgi için Animasyon Oluşturma dokümanlarının tamamını okuyun.
Yaygın composable mülklerini canlandırma
Compose, birçok yaygın animasyon kullanım alanı için çözüm üretmenize olanak tanıyan kullanışlı API'ler sunar. Bu bölümde, bir composable'ın genel özelliklerini nasıl canlandırabileceğiniz gösterilmektedir.
Animasyonun görünmesi / kaybolması
Bir composable'ı gizlemek veya göstermek için AnimatedVisibility
simgesini kullanın. AnimatedVisibility
kapsamındaki çocuklar, kendi giriş veya çıkış geçişleri için Modifier.animateEnterExit()
kullanabilir.
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
öğesinin giriş ve çıkış parametreleri, composable'ın görünüp kaybolduğunda nasıl davranacağını yapılandırmanıza olanak tanır. Daha fazla bilgi için belgelerin tamamını okuyun.
Bir composable'ın görünürlüğünü canlandırmak için bir başka seçenek de animateFloatAsState
ile zaman içinde alfa animasyonu canlandırmaktır:
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) ) { }
Bununla birlikte, alfa sürümünün değiştirilmesi, composable'ın bestede kalacağı ve yerleştirildiği alanı doldurmaya devam edeceği uyarısını da beraberinde getirir. Bu durum, ekran okuyucuların ve diğer erişilebilirlik mekanizmalarının ekrandaki öğeyi değerlendirmeye devam etmesine neden olabilir. Diğer yandan, AnimatedVisibility
sonunda öğeyi besteden kaldırır.
Arka plan rengini canlandır
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()
kullanmaktan daha etkilidir.
Modifier.background()
, tek seferlik renk ayarı için kabul edilebilir ancak bir rengin zaman içinde animasyon oluşturması, gerekenden daha fazla yeniden kompozisyona neden olabilir.
Arka plan renginde sonsuz animasyon uygulamak için animasyon bölümünü tekrarlama konusuna bakın.
composable'ın boyutunu kullanarak
Oluştur, composable'ların boyutunu birkaç farklı şekilde canlandırmanızı sağlar. Oluşturulabilir boyut değişiklikleri arasındaki animasyonlar için animateContentSize()
simgesini kullanın.
Örneğin, birden çok satıra genişletilebilen metin içeren bir kutunuz varsa daha yumuşak bir geçiş için Modifier.animateContentSize()
kullanabilirsiniz:
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 } ) { }
Boyut değişikliklerinin nasıl yapılması gerektiğini açıklamak için bir SizeTransform
ile birlikte AnimatedContent
kullanabilirsiniz.
composable'ın konumunu canlandır
Bir composable'ın konumunu animasyon haline getirmek için Modifier.offset{ }
ile birlikte animateIntOffsetAsState()
öğesini kullanın.
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 } )
Konum veya boyutu canlandırırken composable'ların diğer composable'ların üzerine ya da altına çizilmemesini istiyorsanız Modifier.layout{ }
özelliğini kullanın. Bu değiştirici, boyut ve konum değişikliklerini üst öğeye uygular ve bu da diğer alt öğeleri etkiler.
Örneğin, bir Box
öğesini Column
içinde taşıyorsanız ve diğer alt öğelerin Box
hareket ettiğinde hareket etmesi gerekiyorsa ofset bilgilerini Modifier.layout{ }
ile aşağıdaki gibi ekleyin:
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) ) }
composable'ın dolgusunu canlandırın
Bir composable'ın dolgusuna animasyon eklemek için animateDpAsState
ile birlikte Modifier.padding()
öğesini kullanın:
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 canlandırın
Bir composable'ın yüksekliğini canlandırmak için animateDpAsState
ile Modifier.graphicsLayer{ }
birlikte kullanın. Tek seferlik yükseklik değişiklikleri için Modifier.shadow()
işlevini kullanın. Gölgeye animasyon uyguluyorsanız Modifier.graphicsLayer{ }
değiştiricisini kullanmak daha etkili bir seçenektir.
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'ı kullanarak yükseklik özelliğini her durum için farklı değerlere ayarlayın.
Metin ölçeğini, çevirmeyi veya döndürmeyi canlandır
Metnin ölçeğini, çevrilmesini veya döndürülmesini canlandırırken TextStyle
üzerinde textMotion
parametresini TextMotion.Animated
olarak ayarlayın. Böylece metin animasyonları arasında
daha yumuşak geçiş sağlanır. Metni çevirmek, döndürmek veya ölçeklendirmek için Modifier.graphicsLayer{ }
aracını kullanın.
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 rengine animasyon ekle
Metin rengine animasyon eklemek için BasicText
composable'ında color
lambda'yı 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ş yapma
Farklı composable'lar arasında animasyon yapmak için AnimatedContent
kullanın. Yalnızca composable'lar arasında standart geçiş efekti 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ş/çıkış geçişi türünü gösterecek şekilde özelleştirilebilir. Daha fazla bilgi için AnimatedContent
ile ilgili dokümanları okuyun veya AnimatedContent
üzerindeki bu blog yayınını okuyun.
Farklı hedeflere giderken animasyon uygulama
navigation-compose yapısını kullanırken composable'lar arasındaki geçişleri canlandırmak için bir composable'da enterTransition
ve exitTransition
değerlerini belirtin. Üst düzeydeki tüm hedefler için kullanılacak varsayılan animasyonu da NavHost
ayarlayabilirsiniz:
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( // ... ) } }
Gelen ve giden içeriğe farklı efektler uygulayan birçok farklı giriş/çıkış geçişi türü vardır. Daha fazla bilgi için belgelere bakın.
Animasyonu tekrarlama
Animasyonunuzu sürekli olarak tekrar etmek için infiniteRepeatable
animationSpec
ile rememberInfiniteTransition
kullanın. Nasıl ileri veya geri gitmesi gerektiğini belirtmek için RepeatModes
öğesini değiştirin.
Belirli bir sayıda tekrar etmek 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'ın açılışında animasyon başlatma
LaunchedEffect
, bir composable besteye girdiğinde çalışır. Bir composable'ın başlatılmasında bir animasyon başlatır. Bunu, animasyonun durum değişikliğini sağlamak için kullanabilirsiniz. Başlatma sırasında animasyonu başlatmak için Animatable
ile animateTo
yöntemini kullanma:
val alphaAnimation = remember { Animatable(0f) } LaunchedEffect(Unit) { alphaAnimation.animateTo(1f) } Box( modifier = Modifier.graphicsLayer { alpha = alphaAnimation.value } )
Sıralı animasyonlar oluşturma
Sıralı veya eş zamanlı animasyonlar gerçekleştirmek için Animatable
eş yordam API'lerini kullanın. Animatable
öğesinde animateTo
öğesinin birbiri ardına çağrılması, her animasyonun devam etmeden önce önceki animasyonların tamamlanmasını beklemesine neden olur .
Bunun nedeni, bu fonksiyonun 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
Eşzamanlı animasyonlar elde etmek için eş yordam API'lerini (Animatable#animateTo()
veya animate
) veya Transition
API'yi kullanın. Eş yordam bağlamında birden fazla başlatma işlevi kullanırsanız animasyonlar aynı anda başlatılır:
val alphaAnimation = remember { Animatable(0f) } val yAnimation = remember { Animatable(0f) } LaunchedEffect("animationKey") { launch { alphaAnimation.animateTo(1f) } launch { yAnimation.animateTo(100f) } }
Birçok farklı mülk animasyonunu aynı anda yönlendirmek amacıyla aynı durumu kullanmak için updateTransition
API'yi kullanabilirsiniz. Aşağıdaki örnekte, durum değişikliği ile kontrol edilen iki özellik (rect
ve borderWidth
) canlandırılmaktadır:
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 edin
Oluşturma'daki animasyonlar performans sorunlarına neden olabilir. Bu, animasyonun doğasından kaynaklanır: Hareket illüzyonu yaratmak için ekrandaki pikselleri kare kare hızla taşımak veya değiştirmek.
Oluşturma işleminin farklı aşamalarını göz önünde bulundurun: kompozisyon, düzen ve çizim. Animasyonunuz düzen aşamasını değiştirirse etkilenen tüm composable'ların yeniden düzenlenmesi ve yeniden çizilmesi gerekir. Animasyonunuz çizim aşamasında ortaya çıkarsa, animasyonu düzen aşamasında çalıştırdığınıza göre varsayılan olarak daha iyi performans gösterir, çünkü genel olarak yapılması gereken daha az iş olur.
Uygulamanızın animasyon oluştururken mümkün olduğunca az işlem yapmasını sağlamak için mümkün olduğunda bir Modifier
öğesinin lambda sürümünü seçin. Bu işlem, yeniden oluşturma işlemini atlar ve animasyonu beste aşamasının dışında gerçekleştirir. Aksi takdirde, bu değiştirici her zaman çizim aşamasında çalıştırılacağı için Modifier.graphicsLayer{ }
etiketini kullanın. Bu konu hakkında daha fazla bilgi edinmek için performans belgelerindeki okumaları erteleme bölümüne bakın.
Animasyon zamanlamasını değiştirme
Varsayılan olarak oluşturma işlemi, çoğu animasyon için ilkbahar animasyonlarını kullanır. Yaylar veya fiziğe dayalı
animasyonlar daha doğal görünür. Bu makineler ayrıca sabit bir süre yerine cismin
mevcut hızını hesaba kattığı için kesintiye neden olur.
Varsayılan değeri geçersiz kılmak isterseniz yukarıda gösterilen tüm animasyon API'leri, animasyonun çalışma şeklini özelleştirmek için animationSpec
ayarlama yeteneğine sahiptir. İstediğiniz zaman animasyonun belirli bir süre boyunca yürütülmesini veya daha fazla hareket etmesini sağlayabilirsiniz.
Aşağıda farklı animationSpec
seçeneklerinin bir özeti verilmiştir:
spring
: Fizik kurallarını temel alan animasyon, tüm animasyonlar için varsayılan ayardır. Farklı bir animasyon görünümü ve tarzı elde etmek için sertliği veya sönümleme oranını değiştirebilirsiniz.tween
(arasının kısaltması): Süreye dayalı animasyon,Easing
işleviyle iki değer arasında animasyon yapar.keyframes
: Bir animasyondaki belirli önemli noktalarda değerleri belirtme özelliği.repeatable
: Belirli sayıda çalışan,RepeatMode
tarafından belirtilen süreye dayalı spesifikasyondur.infiniteRepeatable
: Sonsuza kadar çalışacak süreye dayalı spesifikasyon.snap
: Animasyon olmadan anında bitiş değerine tutturur.
animationSpecs hakkında daha fazla bilgi edinmek 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:
- Oluşturma penceresindeki 5 hızlı animasyon
- Compose'da Jellyfish'in hareket etmesini sağlama
- Oluşturma penceresinde
AnimatedContent
özelleştirme - Oluşturma işleminde yumuşak geçiş işlevlerini kolaylaştırma