Oluşturma işleminde birçok yerleşik animasyon mekanizması vardır ve hangisini seçeceğinizi bilmek zor olabilir. Aşağıda, animasyonların yaygın kullanım alanlarını görebilirsiniz. Kullanabileceğiniz farklı API seçeneklerinin tamamı hakkında daha ayrıntılı bilgi için Animasyon Oluşturma dokümanının tamamını okuyun.
Ortak composable özelliklerini canlandırma
Compose, birçok yaygın animasyon kullanım alanını çözmenize olanak tanıyan kullanışlı API'ler sağlar. Bu bölümde, bir bileşimin ortak özelliklerini nasıl canlandırabileceğiniz gösterilmektedir.
Görünme / kaybolma animasyonunu etkinleştirme
Bir Besteci'yi gizlemek veya göstermek için AnimatedVisibility
simgesini kullanın. AnimatedVisibility
içindeki çocuklar, kendi giriş veya çıkış geçişleri için Modifier.animateEnterExit()
öğesini 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
'ün giriş ve çıkış parametreleri, bir composable'ın göründüğünde ve kaybolduğunda nasıl davranacağını yapılandırmanıza olanak tanır. Daha fazla bilgi için tam dokümanları okuyun.
Bir bileşenin görünürlüğünü animasyonlu hale getirmenin bir başka yolu da animateFloatAsState
kullanarak alfa değerini zaman içinde animasyonlu hale getirmektir:
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 alfa değerini değiştirmek, birleştirilebilir öğenin bileşimde kalacağı ve yerleştirildiği alanı kaplamaya devam edeceği anlamına gelir. Bu durum, ekran okuyucuların ve diğer erişilebilirlik mekanizmalarının öğeyi ekranda olarak değerlendirmeye devam etmesine neden olabilir. Öte yandan AnimatedVisibility
, öğeyi nihayetinde kompozisyondan kaldırır.
Arka plan rengini animasyonlu hale getirme
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 yüksek performanslıdır.
Modifier.background()
, tek seferlik bir renk ayarı için kabul edilebilir ancak bir rengin zaman içinde animasyonu yapılırken bu, gerekenden daha fazla yeniden oluşturmaya neden olabilir.
Arka plan rengini sonsuz olarak animasyonlu hale getirmek için animasyonu tekrarlama bölümüne bakın.
Bir composable'ın boyutunu canlandırma
Oluşturma, bileşenlerin boyutunu birkaç farklı şekilde canlandırmanıza olanak tanır. Birleştirilebilir boyut değişiklikleri arasındaki animasyonlar için animateContentSize()
kullanın.
Örneğin, bir satırdan birden fazla satıra genişleyebilecek metin içeren bir kutunuz varsa daha yumuşak bir geçiş elde etmek için Modifier.animateContentSize()
simgesini 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 AnimatedContent
ile birlikte SizeTransform
kullanabilirsiniz.
Bir composable'ın konumunu canlandır
Bir composable'ın konumuna animasyon eklemek için Modifier.offset{ }
öğesini animateIntOffsetAsState()
ile birlikte 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 animasyonlu olarak değiştirirken bileşenlerin diğer bileşenlerin üzerine veya altına çizilmediğinden emin olmak istiyorsanız Modifier.layout{ }
seçeneğini kullanın. Bu değiştirici, boyut ve konum değişikliklerini ebeveyne iletir. Bu da diğer çocukları etkiler.
Örneğin, bir Box
öğesini bir Column
içinde taşıyorsanız ve Box
öğesi taşındığında diğer alt öğelerin de taşınması 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) ) }
Bir bileşenin dolgusunu canlandırma
Bir bileşenin dolgusunu animasyonlu hale getirmek için animateDpAsState
ile birlikte Modifier.padding()
'ü 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 bileşenin yüksekliğini animasyonlu olarak değiştirme
Bir bileşimin yüksekliğini animasyonlu olarak değiştirmek için animateDpAsState
ile birlikte Modifier.graphicsLayer{ }
kullanın. Tek seferlik yükseklik değişiklikleri için Modifier.shadow()
kullanın. Gölgeyi canlandırıyorsanız Modifier.graphicsLayer{ }
değiştiricisini kullanmak daha yüksek performanslı 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
bileşimini kullanın ve yükseklik özelliğini eyalet başına farklı değerlere ayarlayın.
Metin ölçeği, hareket ettirme veya döndürme işlemlerine animasyon ekleme
Metnin ölçeğini, çevirisini veya dönüşünü animasyonlu hale getirirken TextStyle
üzerindeki textMotion
parametresini TextMotion.Animated
olarak ayarlayın. Böylece metin animasyonları arasında daha yumuşak geçişler elde edersiniz. 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 rengini animasyonlu hale getirme
Metin rengini animasyonlu hale getirmek için BasicText
kompozisyonunda color
lambdasını 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ı kompozisyonlar arasında animasyon oluşturmak için AnimatedContent
kullanın. Kompozitörler arasında standart bir solma efekti oluşturmak 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ş ve çıkış geçişi türünü gösterecek şekilde özelleştirilebilir. Daha fazla bilgi için AnimatedContent
ile ilgili dokümanları veya AnimatedContent
ile ilgili bu blog yayınını okuyun.
Farklı hedeflere giderken animasyon gösterme
navigation-compose yapısını kullanırken bileşenler arasındaki geçişleri animasyonlu hale getirmek için bir bileşende enterTransition
ve exitTransition
öğelerini belirtin. Varsayılan animasyonu üst düzeydeki tüm hedefler için kullanılacak şekilde de ayarlayabilirsiniz 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( // ... ) } }
Gelen ve giden içeriğe farklı efektler uygulayan birçok farklı giriş ve çıkış geçişi türü vardır. Daha fazla bilgi için belgelere bakın.
Animasyonu tekrarlama
Animasyonunuzu sürekli olarak tekrarlamak için infiniteRepeatable
animationSpec
ile birlikte rememberInfiniteTransition
kullanın. RepeatModes
değerini değiştirerek nasıl ileri geri gideceğini belirtin.
Belirli bir sayıda tekrarlamak için finiteRepeatable
simgesini 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 bileşenin başlatılmasıyla animasyon başlatma
LaunchedEffect
, bir bileşen bileşime girdiğinde çalışır. Bir bileşenin başlatılmasıyla birlikte bir animasyon başlatır. Animasyon durumunu değiştirmek için bunu kullanabilirsiniz. Animasyonu başlatmak için Animatable
yöntemini animateTo
yöntemiyle birlikte kullanın:
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
coroutine API'lerini kullanın. Animatable
üzerinde animateTo
işlevinin art arda çağrılması, her bir animasyonun devam etmeden önce önceki animasyonların tamamlanmasını beklemesine neden olur .
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ı animasyon oluşturma
Eşzamanlı animasyonlar elde etmek için coroutine API'lerini (Animatable#animateTo()
veya animate
) ya da Transition
API'yi kullanın. Bir coroutine 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) } }
Aynı durumu kullanarak aynı anda birçok farklı tesis animasyonu oluşturmak için updateTransition
API'yi kullanabilirsiniz. Aşağıdaki örnekte, durum değişikliğiyle kontrol edilen iki mülk (rect
ve borderWidth
) animasyonlu olarak gösterilmektedir:
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
Oluşturma bölümündeki animasyonlar performans sorunlarına neden olabilir. Bunun nedeni, animasyonun doğası gereği hareket illüzyonu oluşturmak için ekrandaki pikselleri kare kare hızlı bir şekilde taşımak veya değiştirmektir.
Oluşturma'nın 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üzenlenip yeniden çizilmesi gerekir. Animasyonunuz çizim aşamasında gerçekleşirse varsayılan olarak, animasyonu düzen aşamasında çalıştırdığınızdan daha yüksek performans gösterir. Bunun nedeni, genel olarak daha az iş yapmasıdır.
Uygulamanızın animasyon sırasında mümkün olduğunca az işlem yapması için mümkün olduğunda Modifier
öğesinin lambda sürümünü seçin. Bu, yeniden oluşturma işlemini atlar ve animasyonu oluşturma aşamasının dışında gerçekleştirir. Aksi takdirde, bu değiştirici her zaman çizim aşamasında çalıştığından Modifier.graphicsLayer{ }
kullanın. Bu konuda daha fazla bilgi için performans dokümanlarındaki okuma işlemlerini erteleme bölümüne bakın.
Animasyon zamanlamasını değiştirme
Oluşturma, çoğu animasyon için varsayılan olarak yay animasyonları kullanır. Yaylar veya fiziğe dayalı animasyonlar daha doğal görünür. Ayrıca, sabit bir süre yerine nesnenin mevcut hızını hesaba kattıkları için kesintiye uğratılabilirler.
Varsayılan ayarı geçersiz kılmak istiyorsanız yukarıda gösterilen tüm animasyon API'leri, bir animasyonun nasıl çalışacağını özelleştirmek için animationSpec
ayarlayabilir. Böylece, animasyonun belirli bir süre boyunca yürütülmesini veya daha hareketli olmasını sağlayabilirsiniz.
Farklı animationSpec
seçeneklerinin özeti aşağıda verilmiştir:
spring
: Tüm animasyonlar için varsayılan olan, fiziğe dayalı animasyon. Farklı bir animasyon görünümü ve hissi elde etmek için stiffness veya dampingRatio değerini değiştirebilirsiniz.tween
(arasında): Süreye dayalı animasyon, iki değer arasında birEasing
işleviyle animasyon.keyframes
: Animasyonun belirli önemli noktalarında değerleri belirtmek için kullanılan özellik.repeatable
:RepeatMode
tarafından belirtilen belirli sayıda çalıştırılan, süreye dayalı spesifikasyon.infiniteRepeatable
: Sonsuza kadar çalışan süreye dayalı spesifikasyon.snap
: Animasyon olmadan son değere anında sabitlenir.
animationSpecs hakkında daha fazla bilgi için dokümanların tamamını okuyun.
Ek kaynaklar
Oluşturma'daki eğlenceli animasyonlara dair daha fazla örnek için aşağıdakilere göz atın:
- Oluşturma bölümündeki 5 hızlı animasyon
- Jellyfish'i Oluştur'da hareket ettirme
- Oluştur'da
AnimatedContent
'yi özelleştirme - Oluşturma bölümünde Easing işlevlerini kullanmaya başlama