Android Compose ile Animasyonlar ve Geçişler 📲

Ömer Akkoyun
KoçSistem
Published in
6 min readSep 26, 2023

Compose, geliştiricilere kullanıcı arayüzlerini daha etkili bir şekilde oluşturma ve yönetme imkanı sunarken, animasyonlar ve geçişler gibi görsel özellikler, kullanıcı deneyimini geliştirmenin önemli bir parçasıdır. Bu yazıda, Android Compose kullanarak animasyonları ve geçişleri nasıl yapabileceğimize bakacağız.

🟢 Bölüm 1: Temel Animasyonlar

Compose kullanarak bir renk değişkenini veya animasyonu nasıl işleyebileceğimize bakalım;

Resimde göründüğü gibi TabRow içinde “Home” ve “Work” adında iki adet tab mevcut ve bu tablar arası geçişlerde anasayfanın arkaplan renk geçişi animasyonunu kullanabiliriz.

🟦 Animasyonsuz renk geçişleri:

val backgroundColor = if (tabPage == TabPage.Home) Purple100 else Green300

🟪 Animasyonlu renk geçişleri:

val backgroundColor by animateColorAsState(if (tabPage == TabPage.Home) Purple100 else Green300)

Buradaki “animateColorAsState” geçişlerin animasyonlu bir şekilde olmasını sağlar, verilen başlangıç renk değerini ve hedef renk değerini alır ve bu iki renk arasında yumuşak bir geçiş oluşturur.

🟣 Bölüm 2: Görünüm (Show-Hide) Animasyonları

Görünüm animasyonları, öğelerin görünür veya görünmez olma durumlarında yumuşak bir geçiş sağlar.

Temel Prensipler:

  1. 🟥 State İzleme: Görünüm animasyonları oluştururken, animasyonun hangi durumda tetikleneceğini belirlemek için bir durumu (state) dinlemek önemlidir. Bu durum, öğenin görünür veya görünmez olduğunu belirler.
  2. 🟧 Animasyon İşlevi: Animasyonun kendisi, öğenin görünürlüğünü değiştirirken hangi özelliklerin animasyona tabi tutulacağını tanımlar. Örneğin, öğenin boyutu, konumu veya opaklığı gibi özellikler animasyona dahil edilebilir.
  3. 🟨 Animasyon Değerleri: Animasyon işlevi, öğenin animasyonlu geçişini belirleyen başlangıç ve bitiş değerleri arasında bir geçiş sağlar.

Yukarıdaki resimde gördüğünüz gibi bir FloatingActionButton var ve bu buttonun içinde “EDIT” texti yer almaktadır. Sayfa aşağı scroll edildiğinde “EDIT” metnini gizleyip, sayfa yukarı scroll edildiğinde de gösterelim.

🔹Eğer animasyonsuz bir şekilde bu işlemler yapılacak ise;

if (extended) {
Text(
text = stringResource(R.string.edit),
modifier = Modifier
.padding(start = 8.dp, top = 3.dp)
)
}

🔸 Animasyonlu bir şekilde yapılacak ise;

AnimatedVisibility(extended) {
Text(
text = stringResource(R.string.edit),
modifier = Modifier
.padding(start = 8.dp, top = 3.dp)
)
}

🔺AnimatedVisibility kullanarak böyle animasyonlu bir şekilde görünümü gizleyip tekrardan gösterebiliyoruz.

Animasyonlu bir şekilde gizlenip, gösterilebiliyor.

Bir başka örnek ile devam edelim, yine AnimatedVisibility kullanalım ama bu sefer animasyona “enter” ve “exit” değerlerini de ekleyelim.
Bir uyarı mesajı gösterelim, yukarıdan aşağı doğru açılsın ve aşağıdan yukarı doğru da gizlensin. Bunları da animasyonlu bir şekilde yapalım;

AnimatedVisibility(
visible = isShow, // -> Bu değere bağlı olarak gizle/göster
enter = slideInVertically(), // -> Giriş animasyonu, yukarıdan aşağı
exit = slideOutVertically()// -> Çıkış animasyonu, aşağıdan yukarı
) {
Surface(
modifier = Modifier.fillMaxWidth(),
color = MaterialTheme.colors.secondary,
elevation = 4.dp
) {
Text(
text = stringResource(R.string.edit_message),
modifier = Modifier.padding(16.dp)
)
}
}
Ve sonuç :)

🟠 Bölüm 3: Size-Boyut Değişikliği Animasyonları

Bir butona tıkladığımızda, boyutunun animasyonlu bir şekilde değiştiği basit bir animasyon örneğini yazalım. Kod parçasının nasıl çalıştığını ve hangi temel kavramları içerdiğini anlatmak için aşağıdaki açıklamaları okuyabilirsiniz:

@Composable
fun ButtonWithAnimation() {
// Butonun büyüklüğünü dinlemek için bir durum değişkeni oluşturduk.
var isButtonBig by remember { mutableStateOf(false) }

// Boyutu değiştirmek için Dp üzerinden animasyon kullanacağız.
// Bu yüzden 'animateDpAsState' kullandık.
val size by animateDpAsState(
targetValue = if (isButtonBig) 200.dp else 100.dp, // Boyut hedef değeri
animationSpec = tween( // tween/swing bunlarla ilgili notlar en altta.
durationMillis = 300, // Animasyon süresi (milisaniye)
easing = FastOutSlowInEasing // Animasyon eğrisi (hızlandırma-yavaşlatma)
)
)

// Ana bileşeni bir Box içine aldık (Kotlindeki FrameLayout gibi düşünebilirsiniz.)
Box(
modifier = Modifier
.fillMaxSize()
.padding(16.dp),
contentAlignment = Alignment.Center
) {
// Tıklanabilir bir buton oluşturduk.
Button(
onClick = {
// Butona tıklanıldığında boyut değişkenin değeri ters çevrilsin.
isButtonBig = !isButtonBig
},
modifier = Modifier
.size(size) // Boyutu, yukarıda oluşturduğumuz animasyonlu boyuta bağladık.
.background(Color.Blue)
.padding(16.dp)
) {
Text(text = "Click me")
}
}
}
Sonuç

🔵 Bölüm 4: Tekrarlanan (Repeating) Animasyonlar

Bazı senaryolarda animasyonların belli durumda tekrar etmesini isteyebiliriz. Bu, kullanıcı deneyimini zenginleştirmek ve kullanıcıların dikkatini çekmek için sıklıkla kullanılan bir tekniktir.Özellikle, “infiniteRepeatable” işlevi, animasyonların sonsuz bir şekilde yinelemesini sağlamak için kullanılır.

Örneğin, bir uygulama simgesini düşünün, kullanıcı bu simgeye tıkladığında, simge üzerinde sürekli bir parlama veya vurgulama efekti görmek isteyebiliriz. Yada bir loading durumunda kullanıcıya animasyonlu bir şekilde yüklencek detayların olduğu alana yükleniyor efekti verebiliriz.

Animasyonsuz loading

Resimde de göründüğü gibi datalar gelene kadar, alanlar gri bir renk ile gösteriliyor. Bunu daha estetik göstermek için bu alanların alpha değerlerini datalar gelene kadar infiniteRepeatable animasyon ile göstermeye çalışalım;

val infiniteTransition = rememberInfiniteTransition()
val alpha by infiniteTransition.animateFloat(
initialValue = 0f,
targetValue = 1f,
animationSpec = infiniteRepeatable(
animation = keyframes {
durationMillis = 1000
0.7f at 500
},
repeatMode = RepeatMode.Reverse
)
)

Bu şekilde yaptıktan sonra tekrar bakalım;

Data gelene kadar ilgili alanın alpha değerleri sonsuz animasyon ile gösteriliyor.

Son Notlar:

🟠 “spring” Animasyonu

  • Yay tipi animasyonlarda kullanılır. Bu, ani ve elastik animasyonlar için uygundur.
  • Nesne, hedef değere daha hızlı yaklaşır ve sonunda biraz geri sallanabilir (bouncy).
  • Doğal bir yay gibi davranan animasyonlar için uygundur ve gerçek dünyadaki fiziksel nesnelerin hareketini taklit eder.
  • Daha elastik ve canlı bir animasyon hissi verir.
  • Örnek kullanım: Yaylanmalı bir şekilde boyut değişen bir nesne animasyonu.
animationSpec =spring(dampingRatio=Spring.DampingRatioLowBouncy,stiffness = Spring.StiffnessLow)

dampingRatio, bir yayın sönümleme seviyesini ifade eder. Yüksek bir sönümleme oranı, animasyonun daha hızlı durmasına ve daha az geri sallanmasına neden olur. Düşük bir sönümleme oranı ise daha fazla geri sallanma ve daha uzun bir süre boyunca animasyonun devam etmesine yol açar.

stiffness, bir yayın sertlik seviyesini ifade eder. Yüksek bir sertlik, animasyonun daha hızlı ve sert olmasına neden olur. Düşük bir sertlik ise daha yavaş ve yumuşak bir animasyonu sağlar.

🔴 “tween” Animasyonu:

  • Yavaş ve sabit bir hızda ilerleyen animasyonlar için kullanılır. Bu, düzgün ve istikrarlı bir animasyon için uygundur.
  • Hedef değere doğru sabit bir hızla ilerler, geri sallanma (bounce) yoktur.
  • Kullanımı daha basit ve öngörülebilirdir.
  • Belirli bir zaman diliminde nesnenin belirli bir değere ne kadar sürede ulaşması gerektiğini kontrol etmek için uygundur.
  • Örnek kullanım: Sayılar arasında geçiş yapan bir sayaç animasyonu.
animationSpec = tween(durationMillis = 1000,easing = LinearEasing)

Easing animasyonların başlangıçtan bitişe doğru hızlarının nasıl değişeceğini kontrol etmek için kullanılan bir özelliktir. Animasyonlar, objelerin veya özelliklerin belirli bir süre boyunca bir başlangıç değerinden bir bitiş değerine geçmesini simüle ederler. Bu geçiş sırasında, animasyonun hızı veya ivmesi değiştirilebilir ve bu işlemi yapabilmek için “easing” kullanılır.

Easing, animasyonun daha doğal, akıcı ve hoş görünmesini sağlar. Özellikle hızın ani değişimleri veya sabit hızlarda animasyonlar yerine, nesnelerin yavaş başlama ve durma, hızlarının değişmesi gibi etkilerin uygulanmasını sağlar.

Easing türleri, animasyonlarda nasıl bir hız değişimi istediğinize bağlı olarak farklıdır. İşte bazı yaygın easing türleri:

  1. 🟥 Linear Easing (Doğrusal Easing): Bu, animasyonun başlangıçtan sona kadar sabit bir hızda hareket ettiği basit bir easing türüdür. Hız sabittir ve ani değişimler yoktur.
  2. 🟧 Ease-In: Animasyonun başlangıçta yavaşladığı ve sonra hızlandığı bir easing türüdür. Nesne yavaş başlar ve hızı artar.
  3. 🟨 Ease-Out: Animasyonun başlangıçta hızlı olduğu ve sonra yavaşladığı bir easing türüdür. Nesne hızlı başlar ve hızı azalır.
  4. 🟩 Ease-In-Out: Animasyonun hem başlangıçta hem de sonunda yavaşladığı, ortasında ise hızlandığı bir easing türüdür. Bu, animasyonun daha doğal bir hareket izlemesini sağlar.
  5. 🟦 Bounce Easing (Sıçrama Easing): Nesnelerin sona doğru ilerlerken sıçradığı, geri tepme benzeri bir etki yaratan bir easing türüdür. Özellikle nesnelerin yere düşerken veya yaylanırken kullanışlıdır.
  6. 🟪 Elastic Easing (Elastik Easing): Animasyonun sonunda bir tür elastik geri tepme etkisi yaratan bir easing türüdür. Bu, nesnelerin sona doğru hızla yaklaştığını ancak biraz geri sıçradığını simgeler.
Swing, daha karmaşık ve fiziksel animasyonlar oluşturmak için tercih edilir.

Sonuç:

Bu yazıda, Android Compose ile animasyonların ve geçişlerin nasıl oluşturulacağını ve kullanılacağını öğrendik. Animasyonların kullanıcı deneyimini nasıl zenginleştirebileceğini gördük. Compose ile daha fazla animasyon öğrenmek için Android’in resmi sayfasından yararlanabilirsiniz.

Kaynak: Android Compose Animation

Bir sonraki yazıda görüşmek üzere 😊

--

--