# Jetpack Compose: Adım Adım İleri Düzey Animasyonlar > Compose'da ileri düzey animasyonlar için kapsamlı rehber: geçişler, AnimatedVisibility, Animatable, hareketler ve akıcı Android arayüzleri için performans. - Published: 2026-02-08 - Updated: 2026-04-28 - Author: SharpSkill - Tags: jetpack compose, android, animations, kotlin, ui - Reading time: 12 min --- Animasyonlar, işlevsel bir uygulamayı akılda kalıcı bir kullanıcı deneyimine dönüştürür. Jetpack Compose, akıcı arayüz oluşturmayı önemli ölçüde basitleştiren güçlü bir bildirimsel animasyon API'si sunar. Bu rehber, performanslı ve sürdürülebilir animasyonlar oluşturmak için ileri düzey teknikleri ele alır. > **Ön koşullar** > > Bu eğitim, Compose temellerine (recomposition, state, modifier) aşinalık varsayar. Temeller için önce Jetpack Compose mülakat soruları rehberine göz atmak yararlı olur. ## Compose'da Animasyon API Temelleri Compose, animasyonlar için birkaç API seviyesi sunar. Seçim, istenen kontrol seviyesine ve animasyonun karmaşıklığına bağlıdır. API üç ana kategoriye ayrılır: yüksek seviyeli animasyonlar (`AnimatedVisibility`, `AnimatedContent`), durum tabanlı animasyonlar (`animate*AsState`) ve düşük seviyeli animasyonlar (`Animatable`, `Transition`). ```kotlin // AnimationLevels.kt // Overview of the three animation API levels @Composable fun AnimationApiOverview() { // High level: simple predefined animations AnimatedVisibility(visible = isVisible) { Text("Animated content") } // Intermediate level: state-driven animation val alpha by animateFloatAsState( targetValue = if (isSelected) 1f else 0.5f, label = "alpha" ) // Low level: full control over animation val animatable = remember { Animatable(0f) } LaunchedEffect(targetValue) { animatable.animateTo(targetValue) } } ``` Doğru API seviyesini seçmek, gerekli esnekliği korurken okunabilir kod tutmak için kritiktir. ## AnimatedVisibility: Zarif Giriş ve Çıkış Animasyonları `AnimatedVisibility`, öğelerin görünme ve kaybolmalarını canlandırmak için ideal başlangıç noktasıdır. Bu API, içeriğin oluşturulmasını ve ayrıştırılmasını otomatik olarak yönetir. `enter` ve `exit` parametreleri, animasyon davranışını tanımlayan geçiş kombinasyonlarını kabul eder. Bu geçişler `+` operatörü ile birleştirilebilir. ```kotlin // AnimatedVisibilityExample.kt @Composable fun ExpandableCard( title: String, content: String, modifier: Modifier = Modifier ) { var isExpanded by remember { mutableStateOf(false) } Card( modifier = modifier.clickable { isExpanded = !isExpanded } ) { Column(modifier = Modifier.padding(16.dp)) { Row( modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween ) { Text(text = title, style = MaterialTheme.typography.titleMedium) Icon( imageVector = if (isExpanded) Icons.Default.ExpandLess else Icons.Default.ExpandMore, contentDescription = null ) } // Expansion animation with fade + slide AnimatedVisibility( visible = isExpanded, enter = fadeIn(animationSpec = tween(300)) + expandVertically(animationSpec = tween(300)), exit = fadeOut(animationSpec = tween(200)) + shrinkVertically(animationSpec = tween(200)) ) { Text( text = content, modifier = Modifier.padding(top = 12.dp), style = MaterialTheme.typography.bodyMedium ) } } } } ``` `AnimatedVisibility` içindeki içerik yalnızca `visible = true` olduğunda oluşturulur ve bu durum, çok sayıda genişletilebilir öğe içeren listelerde performansı optimize eder. > **Geçişleri birleştirme** > > Kullanılabilir geçişler arasında `fadeIn/fadeOut`, `slideIn/slideOut`, `expandIn/shrinkOut`, `scaleIn/scaleOut` bulunur. Özel efektler oluşturmak için serbestçe birleştirilebilirler. ## animate*AsState: Durum Odaklı Animasyonlar `animate*AsState` fonksiyon ailesi, ilkel değerlerdeki değişiklikleri otomatik olarak canlandırır. Compose'daki basit animasyonlar için en deyimsel yaklaşımdır. Her veri türünün kendine özel bir fonksiyonu vardır: `animateColorAsState`, `animateFloatAsState`, `animateDpAsState`, `animateIntAsState` vb. ```kotlin // AnimateAsStateExample.kt @Composable fun InteractiveButton( isSelected: Boolean, onClick: () -> Unit, modifier: Modifier = Modifier ) { // Animated background color val backgroundColor by animateColorAsState( targetValue = if (isSelected) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.surfaceVariant, animationSpec = tween(durationMillis = 250), label = "backgroundColor" ) // Animated elevation val elevation by animateDpAsState( targetValue = if (isSelected) 8.dp else 2.dp, animationSpec = spring( dampingRatio = Spring.DampingRatioMediumBouncy, stiffness = Spring.StiffnessLow ), label = "elevation" ) // Animated text size val textSize by animateFloatAsState( targetValue = if (isSelected) 18f else 14f, label = "textSize" ) Surface( modifier = modifier.clickable(onClick = onClick), color = backgroundColor, shadowElevation = elevation, shape = RoundedCornerShape(12.dp) ) { Text( text = if (isSelected) "Selected" else "Select", modifier = Modifier.padding(horizontal = 24.dp, vertical = 12.dp), fontSize = textSize.sp ) } } ``` `animationSpec` parametresi, animasyonun zamanlama davranışını kontrol eder. En çok kullanılan iki spec, `tween` (easing ile sabit süre) ve `spring` (sıçramalı gerçekçi fizik) şeklindedir. ## Transition: Birden Çok Animasyonu Düzenlemek Birden fazla özellik koordineli bir şekilde canlandırılması gerektiğinde, `updateTransition` merkezi kontrol sağlar. Bu API, tüm animasyonların senkronize kalmasını garanti eder. Desen, bir enum durumu tanımlamayı ve ardından bu duruma bağlı her özellik için animasyon oluşturmayı içerir. ```kotlin // TransitionExample.kt // Card state: defines visual behavior enum class CardState { Collapsed, Expanded, Selected } @Composable fun AnimatedStateCard( cardState: CardState, modifier: Modifier = Modifier ) { // Central transition coordinating all animations val transition = updateTransition( targetState = cardState, label = "cardTransition" ) // Card height based on state val cardHeight by transition.animateDp( transitionSpec = { spring(stiffness = Spring.StiffnessLow) }, label = "height" ) { state -> when (state) { CardState.Collapsed -> 80.dp CardState.Expanded -> 200.dp CardState.Selected -> 160.dp } } // Border color based on state val borderColor by transition.animateColor( transitionSpec = { tween(300) }, label = "borderColor" ) { state -> when (state) { CardState.Collapsed -> Color.Transparent CardState.Expanded -> MaterialTheme.colorScheme.outline CardState.Selected -> MaterialTheme.colorScheme.primary } } // Corner radius based on state val cornerRadius by transition.animateDp( label = "cornerRadius" ) { state -> when (state) { CardState.Collapsed -> 8.dp CardState.Expanded -> 16.dp CardState.Selected -> 24.dp } } Card( modifier = modifier .height(cardHeight) .border(2.dp, borderColor, RoundedCornerShape(cornerRadius)), shape = RoundedCornerShape(cornerRadius) ) { // Card content } } ``` ## Animatable: Animasyon Üzerinde Tam Kontrol `Animatable`, tam programatik kontrol sağlayan düşük seviyeli API'dir. Bu yaklaşım, kesintiye uğratılabilir animasyonlar, hareketler veya karmaşık senaryolar için gereklidir. `animate*AsState`'in aksine, `Animatable` devam eden bir animasyonu bitmesini beklemeden durdurmayı, tersine çevirmeyi veya değiştirmeyi mümkün kılar. ```kotlin // AnimatableExample.kt @Composable fun SwipeableCard( onDismiss: () -> Unit, modifier: Modifier = Modifier, content: @Composable () -> Unit ) { // Horizontal offset controlled by Animatable val offsetX = remember { Animatable(0f) } val scope = rememberCoroutineScope() // Swipe threshold to trigger dismissal val dismissThreshold = 300f Box( modifier = modifier .offset { IntOffset(offsetX.value.roundToInt(), 0) } .pointerInput(Unit) { detectHorizontalDragGestures( onDragEnd = { scope.launch { if (abs(offsetX.value) > dismissThreshold) { // Animate out then callback val target = if (offsetX.value > 0) 1000f else -1000f offsetX.animateTo( targetValue = target, animationSpec = tween(200) ) onDismiss() } else { // Return to initial position with spring offsetX.animateTo( targetValue = 0f, animationSpec = spring( dampingRatio = Spring.DampingRatioMediumBouncy ) ) } } }, onHorizontalDrag = { _, dragAmount -> scope.launch { // snapTo for instant finger tracking offsetX.snapTo(offsetX.value + dragAmount) } } ) } ) { content() } } ``` `Animatable`'ın temel yöntemleri `animateTo()` (bir hedefe doğru animasyon), `snapTo()` (anlık değişim) ve `stop()` (kesinti) şeklindedir. ## AnimatedContent: İçerik Geçişleri `AnimatedContent`, farklı içerikler arasındaki geçişleri canlandırır. Bu API, görüntülenen arayüzü tamamen değiştiren durum değişiklikleri için mükemmeldir. `targetState` anahtarı, bir geçişin ne zaman gerçekleşeceğini belirler. `transitionSpec`, çıkan ve giren içeriğin nasıl etkileşime gireceğini tanımlar. ```kotlin // AnimatedContentExample.kt @Composable fun CounterWithAnimation( count: Int, modifier: Modifier = Modifier ) { AnimatedContent( targetState = count, modifier = modifier, transitionSpec = { // Determine animation direction val direction = if (targetState > initialState) { // New number enters from top slideInVertically { height -> -height } + fadeIn() togetherWith slideOutVertically { height -> height } + fadeOut() } else { // New number enters from bottom slideInVertically { height -> height } + fadeIn() togetherWith slideOutVertically { height -> -height } + fadeOut() } direction.using(SizeTransform(clip = false)) }, label = "counter" ) { targetCount -> Text( text = "$targetCount", style = MaterialTheme.typography.displayLarge, fontWeight = FontWeight.Bold ) } } ``` > **AnimatedContent ile performans** > > `AnimatedContent` içindeki içerik, her `targetState` değişikliğinde yeniden oluşturulur. Karmaşık içerik için maliyetli öğeleri belleğe almak veya uygun bir anahtar stratejisi kullanmak yararlıdır. ## rememberInfiniteTransition ile Sonsuz Animasyonlar Döngü halindeki animasyonlar (yükleme göstergeleri, nabız efektleri) için `rememberInfiniteTransition`, manuel döngü yönetimi gerektirmeyen özel bir API sunar. ```kotlin // InfiniteTransitionExample.kt @Composable fun PulsingDot( color: Color = MaterialTheme.colorScheme.primary, modifier: Modifier = Modifier ) { val infiniteTransition = rememberInfiniteTransition(label = "pulse") // Looping scale animation val scale by infiniteTransition.animateFloat( initialValue = 0.8f, targetValue = 1.2f, animationSpec = infiniteRepeatable( animation = tween(600, easing = FastOutSlowInEasing), repeatMode = RepeatMode.Reverse ), label = "scale" ) // Synchronized opacity animation val alpha by infiniteTransition.animateFloat( initialValue = 0.5f, targetValue = 1f, animationSpec = infiniteRepeatable( animation = tween(600, easing = FastOutSlowInEasing), repeatMode = RepeatMode.Reverse ), label = "alpha" ) Box( modifier = modifier .size(24.dp) .scale(scale) .alpha(alpha) .background(color = color, shape = CircleShape) ) } ``` ## LazyColumn ile Liste Animasyonları Liste öğeleri için animasyonlar özel ilgi gerektirir. `animateItem()` modifier'ı (eskiden `animateItemPlacement`), yeniden sıralamaları otomatik olarak canlandırır. ```kotlin // ListAnimationExample.kt @Composable fun AnimatedTaskList( tasks: List, onToggle: (Task) -> Unit, onDelete: (Task) -> Unit, modifier: Modifier = Modifier ) { LazyColumn( modifier = modifier, verticalArrangement = Arrangement.spacedBy(8.dp) ) { items( items = tasks, key = { it.id } // Stable key required for animateItem ) { task -> var isVisible by remember { mutableStateOf(true) } // Exit animation before deletion AnimatedVisibility( visible = isVisible, exit = shrinkVertically() + fadeOut() ) { TaskItem( task = task, onToggle = { onToggle(task) }, onDelete = { isVisible = false // Delay to let animation complete }, modifier = Modifier.animateItem( fadeInSpec = tween(300), fadeOutSpec = tween(300), placementSpec = spring( dampingRatio = Spring.DampingRatioMediumBouncy, stiffness = Spring.StiffnessLow ) ) ) } // Trigger deletion after animation LaunchedEffect(isVisible) { if (!isVisible) { delay(300) onDelete(task) } } } } } ``` > **Liste animasyonları için kararlı anahtarlar** > > Kararlı bir `key` parametresi olmadan `animateItem`, öğeleri yeniden bestelemeler arasında izleyemez. Liste indeksi yerine benzersiz bir kimlik kullanılmalı. ## Canvas Animasyonları Özel görsel efektler için `Canvas`'ı animasyonlu değerlerle birleştirmek tam esneklik sunar. ```kotlin // CanvasAnimationExample.kt @Composable fun AnimatedProgressRing( progress: Float, // 0f to 1f modifier: Modifier = Modifier ) { // Progress animation with spring for natural feel val animatedProgress by animateFloatAsState( targetValue = progress, animationSpec = spring( dampingRatio = Spring.DampingRatioLowBouncy, stiffness = Spring.StiffnessVeryLow ), label = "progress" ) // Continuous rotation animation val infiniteTransition = rememberInfiniteTransition(label = "rotation") val rotation by infiniteTransition.animateFloat( initialValue = 0f, targetValue = 360f, animationSpec = infiniteRepeatable( animation = tween(2000, easing = LinearEasing) ), label = "rotation" ) val primaryColor = MaterialTheme.colorScheme.primary val trackColor = MaterialTheme.colorScheme.surfaceVariant Canvas( modifier = modifier .size(120.dp) .rotate(rotation) ) { val strokeWidth = 12.dp.toPx() val radius = (size.minDimension - strokeWidth) / 2 // Background circle (track) drawCircle( color = trackColor, radius = radius, style = Stroke(width = strokeWidth, cap = StrokeCap.Round) ) // Animated progress arc drawArc( color = primaryColor, startAngle = -90f, sweepAngle = animatedProgress * 360f, useCenter = false, style = Stroke(width = strokeWidth, cap = StrokeCap.Round), topLeft = Offset(strokeWidth / 2, strokeWidth / 2), size = Size(radius * 2, radius * 2) ) } } ``` ## Animasyon Performans Optimizasyonu Kötü optimize edilmiş animasyonlar takılmalara yol açabilir ve pili tüketebilir. 60 FPS'i korumak için en iyi uygulamalar şöyle. İlk kural, animasyon sırasında tahsislerden kaçınmaktır. Yeniden bestelemeleri tetikleyen modifier'lar yerine `graphicsLayer` kullanılmalı. ```kotlin // PerformanceOptimization.kt @Composable fun OptimizedAnimatedCard( isExpanded: Boolean, modifier: Modifier = Modifier ) { val scale by animateFloatAsState( targetValue = if (isExpanded) 1.1f else 1f, label = "scale" ) val alpha by animateFloatAsState( targetValue = if (isExpanded) 1f else 0.8f, label = "alpha" ) Card( modifier = modifier // ✅ graphicsLayer: GPU modifications without recomposition .graphicsLayer { scaleX = scale scaleY = scale this.alpha = alpha } // ❌ Avoid: .scale(scale).alpha(alpha) // These modifiers trigger recompositions ) { Text("Card content") } } // Example with remembered lambda to avoid allocations @Composable fun OptimizedClickableItem( onClick: () -> Unit, content: @Composable () -> Unit ) { // ✅ Stable remembered lambda val interactionSource = remember { MutableInteractionSource() } Box( modifier = Modifier .clickable( interactionSource = interactionSource, indication = ripple(), onClick = onClick ) ) { content() } } ``` İkinci kritik nokta listelerdeki animasyonlardır. Eş zamanlı animasyon sayısı sınırlandırılmalı ve türetilmiş hesaplamalar için `derivedStateOf` kullanılmalı. ```kotlin // ListPerformance.kt @Composable fun PerformantAnimatedList( items: List, modifier: Modifier = Modifier ) { // Calculate once whether the list is empty val isEmpty by remember { derivedStateOf { items.isEmpty() } } LazyColumn(modifier = modifier) { items( items = items, key = { it.id } ) { item -> // Lightweight animation only on initial appearance var hasAppeared by remember { mutableStateOf(false) } LaunchedEffect(Unit) { hasAppeared = true } val alpha by animateFloatAsState( targetValue = if (hasAppeared) 1f else 0f, animationSpec = tween(200), label = "itemAlpha" ) ItemCard( item = item, modifier = Modifier.graphicsLayer { this.alpha = alpha } ) } } } ``` ## Sonuç Jetpack Compose'daki animasyonlar, kullanım kolaylığı ile ileri düzey kontrol arasında bir denge sunar. Akılda tutulması gereken anahtar noktalar: - ✅ Karmaşıklığa göre uygun API seviyesini seçmek (AnimatedVisibility → animate*AsState → Animatable) - ✅ İlişkili birden çok animasyonu koordine etmek için `updateTransition` kullanmak - ✅ Doğal animasyonlar için `spring`, kesin süreler için `tween` tercih etmek - ✅ Liste animasyonları için her zaman kararlı bir `key` parametresi sağlamak - ✅ Gereksiz yeniden bestelemeleri önlemek için `graphicsLayer` ile optimize etmek - ✅ Performansı doğrulamak için animasyonları gerçek cihazlarda test etmek Compose animasyonlarına hakim olmak, profesyonel Android uygulamalarını ayırt eder. Performansa dikkat ile birleştirilen bu teknikler, akıcı ve etkileyici kullanıcı deneyimleri oluşturmayı mümkün kılar. --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/tr/blog/android/jetpack-compose-advanced-animations