Jetpack Compose İle Animasyon I

Ömer Durmaz
6 min readDec 17, 2022

Merhaba, bu yazımızda Jetpack Compose ile animasyon geliştirmeden bahsedeceğiz. Android üzerinde kendimiz animasyon geliştirmek istediğimizde bunu xml kodları ile yapabiliyorduk. Ancak bu işlem bana hiçbir zaman cazip gelmediği için kendi animasyonumu kendim geliştirmedim. Bu sebeple geliştiriciler arasında bilinen bir kütüphane olan Lottie Files kullanmayı tercih ettim.

Ancak Jetpack Compose her açıdan geliştirmeye kolaylık sağladığı gibi animasyonlar için de paylaştığı dokümanla, kendi animasyonlarımızı nasıl kolayca geliştirebileceğimizi bize göstermiş oldu. Hadi bu dokümana yakından bakalım;

İhtiyaç belirleme

Öncelikle ekranda göstermek istediğimiz animasyon için ihtiyacımızı belirlemeliyiz. Aşağıdaki şemayı inceleyerek ihtiyacını belirleyebilir, ihtiyacın olan animasyon başlığına giderek geliştirmeni yapabilirsin.

Not: Animasyon yazısı iki parça olacağı için aradığın animasyon yöntemini bu yazıda bulamazsan diğer yazıyı kontrol etmeni öneririm.

İhtiyaç Belirleme Şeması

Üst Düzey Animasyon API’ leri

Jetpack Compose birçok uygulamada kullanılan çeşitli yaygın animasyon kalıpları için bu api’ leri oluşturmuştur. Bu api’ ler Material Design Motion uygulamalarıyla uyumlu olacak şekilde uyarlanmıştır.

AnimatedVisibility

AnimatedVisibility içeriğin gösterilmesini ve gizlenmesini anime eder.

İçine koyduğumuz herhangi bir viewi animasyonlu bir şekilde gösterip gizlemek bu kadar kolay.

Peki bu gösterip gizleme işleminde tam olarak ne gerçekleşiyor?

Aslında view gösterilip gizlenirken EnterTransition ve ExitTransition dediğimiz iki işlem gerçekleşiyor. Eğer herhangi bir özelleştirme yapmazsan exit ve enter transitionları varsayılan değerleri kullanacaktır, ki bunlar gösterirken transparanlık artarak genişleme, gizlerken solarak daralma işlemleridir. Eğer bu enter ve exit transitionları özelleştirmek istersek;

Yukarıda göreceğin üzere enter transitionda birden fazla transition methodlarını birleştirerek karma bir geçiş oluşturabiliriz. Diğer Enter ve Exit transition method tiplerini aşağıda bulabilirsin;

EnterTransition:

fadeIn
slideIn
slideInHorizontally
slideInVertically
scaleIn
expandIn
expandHorizontally
expandVertically

ExitTransition:

fadeOut
slideOut
slideOutHorizontally
slideOutVertically
scaleOut
shrinkOut
shrinkHorizontally
shrinkVertically

Animasyonu otomatik başlatma:

Farz edelim ki ekran açıldığı anda animasyonun çalışmasını istiyorsun. Bu durumda da AnimatedVisiblity bize MutableTransitionState özelliğini sunuyor;

Yukarıda da görüleceği üzere MutableTransitionState parametresinin stateini dinleyerek değişikliğe göre text içinde ki değerleri değiştirebiliriz.

İç içe viewler için animasyon özelleştirme:

Farz edelim ki AnimatedVisibility kullandık ve genel enter ve exit animasyon fadeIn ve fadeOut. Ancak ek olarak içinde bulunan child viewin farklı bir şekilde gelmesini ve gitmesini istiyoruz. Bu tarz durumlar için aşağıdaki yöntemi kullanabiliriz:

Bazı durumlarda ise AnimatedVisibility içindeki view gruplarının her birinin kendine özgü bir enter ve exit transitionu olsun istersek ve genel animasyonu kapatmak istersek; AnimatedVisibility exit değerini ExitTransition.None , enter değerini EnterTransition.None şeklinde ayarlamamız yeterli olacaktır.

Özelleştirilmiş Animasyon Ekleme:

AnimatedVisiblity içinde enter ve exit transitionları gerçekleştiği süreçte kendi animasyonlarımızı da oluşturabiliriz. Yukarıda animasyon stateini dinleyebildiğimizden bahsetmiştik. Bu state süreçlerinde uygulayacağımız değişikler sayesinde özelleştirilmiş bir animasyon oluşturmuş olacağız:

animate*AsState

animate*AsState bir viewe animasyon eklemek için en basit yöntem denilebilir. Sadece başlangıç ve bitiş (hedef) değerleri vermemiz yeterli oluyor. Aşağıdaki örnekte kullandığımız animateFloatAsState methodunda anime edeceği başlangıç ve bitiş değerlerini verdik ve Başka bir state parametresi değiştiğinde bu method iki değer arasında animasyon oluşturacak.

Yukarıdaki örnekteki gibi Compose animate*AsState methodu Float ,Color ,Dp ,Size ,Offset ,Rect ,Int ,IntOffset ve IntSize tiplerini desteklemektedir. TwoWayConverter kullanarak animateValueAsState methodunu çalıştırabilirsin ve bu sayede generiz bir animasyon da oluşturabilirsin.

Dipnot: Bu yazıda bahsedilmeyecek ancak Jetpack Compose ile Animasyon II yazısında değineceğimiz AnimationSpec yöntemi ile animate*AsState methodunu özelleştirebilirsin.

Animated Content

AnimatedContent başlangıç olarak verdiğimiz değer ile hedef olarak güncellediğimiz değerleri güncellerken geçiş animasyonu oluşturur.

Yukarıda görüldüğü üzere başlangıç değeri 0 olan bir değişken butona her tıklandığında bir arttırılıyor. Değer her güncellendiğinde ise AnimatedContent eski değerden yeni değere geçişte bir geçiş animasyonu çalıştırıyor.

AnimatedContent varsayılan geçiş transitionları fadeOut ve fadeIn’ dir. Eğer bu transitionları özelleştirmek istersek;

Yukarıdaki kodun çıktısı

Yukarıdaki kodu ve çıktısına baktığımızda EnterTransition hedef değerin gireceği animasyonu, ExitTransition ise mevcut değerin çıkacağı animasyonu belirlememize yarıyor. Şimdiye kadar bu yöntemlerin AnimatedVisiblity ve AnimatedContent apilerinde kullanıldığını gördük.

SizeTransform:

SizeTransform tahmin edebileceğiniz üzere içinde bulunan viewlerin boyutu değiştiğinde bu değişikliği anime edebilmek için kullanılan yöntemdir.

Yukarıdaki kodun çıktısı

Dipnot: AnimatedVisibility de kullanabildiğimiz şekilde bu yöntemde de enter/exit transitionları içinde bulundan child viewlere ayrı olarak tanımlayabiliriz.

Dipnot: AnimatedVisibility de kullanabildiğimiz şekilde bu yöntemde de özelleştirilmiş animasyonlar kullanabiliriz.

animateContentSize

animateContentSize içerik değişikliğini anime eder.

updateTransition

Transition birden fazla animasyonu çocukları olarak yönetir ve herhangi bir state değişikliğinde bu animasyonları eş zamanlı olarak çalıştırır. Transition değerinin illa ki boolean ya da string gibi bir veri tipi olmasına da gerek yoktur. enum bir tip oluşturarak bunu da state olarak verebiliriz.

enum class BoxState {
Collapsed,
Expanded
}

updateTransition bir transition instance i oluşturur ve bunu hafızada tutar. Herhangi bir güncellemede de state gibi günceller.

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

transition parametresindne herhangi bir animate* extension methodunu çağırarak bir transition oluşturabiliriz. Bu extension methodlar geriye bir animasyon parametresi dönerler. transitionun bağlı olduğu state her değiştiğinde bu child animasyonlar çalışırlar.

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

Opsiyonel olarak oluşturduğun animasyon methodlarının içinde transactionSpec parametresi ekleyerek animasyonu özelleştirebilirsin.

val color by transition.animateColor(
transitionSpec = {
when {
BoxState.Expanded isTransitioningTo BoxState.Collapsed ->
spring(stiffness = 50f)
else ->
tween(durationMillis = 500)
}
}
) { state ->
when (state) {
BoxState.Collapsed -> MaterialTheme.colors.primary
BoxState.Expanded -> MaterialTheme.colors.background
}
}

Transition methodunu AnimatedVisibility ve AnimatedContent ile kullanma:

AnimatedVisibility ve AnimatedContent methodları tek kullanımlarının dışında ayrıca Transition için extension methodları da bulunur. Nasıl ki yukarıda bahsettiğimiz color, dp.. değerlerini tek bir transition parametresiyle aynı anda anime edebiliyorsak bu iki methodu da aynı anda tek bir yerden çalıştırabiliriz.

Generic bir Transition oluşturarak tekrar kullanılabilir yapma:

Basit projelerde animasyon geliştirirken ihtiyaç duyulmasa da karmaşık projelerde kodun okunabilirliği ve tekrar kullanılabilirliği açısından bu tarz yaklaşımlar çok önemlidir. Aşağıda göreceğin örnekteki gibi:

Yukarıda da görüldüğü üzere updateTransitionData methodu oluşturduğumuz TransitionData class tipinde değer dönerek generic bir transition yöntemi oluşturmamıza yarıyor. Bu yöntem sayesinde ilerleyen zamanda üçüncü ya da dördüncü bir view e animasyon eklemek istersek TransitionData classına parametre eklemek ve updateTransitionData methodunda bu parametreyi doldurmak yeterli olacaktır.

Crossfade

CrossFade bir layouttan diğer layouta geçişte crossfade animasyonunu uygular. Her değişiklikte crossfade animasyonu ile layout değişikliği olur.

rememberInfiniteTransition

InfiniteTransition Transition gibi bir ya da daha fazla animasyonu içinde birleştirebilir. Ancak unutulmamalıdır ki animasyon view oluştuğu anda başlar ve view ekrandan kaldırılana kadar sonsuz bir şekilde çalışmaya devam eder. rememberInfiniteTransition methodu ile bir instance oluşturup sonsuz döngülü animasyonu başlatabilirsin. İç animasyonlar animateColor , animateFloat ya da animatedValue methodlarıyla animasyon oluşturulur. Ayrıca infiniteRepeatable ile döngüyü özelleştirebilirsin.

Jetpack Compose ile Animasyon yazımızın birinci kısmının sonuna geldik. İkinci kısımda düşük seviye animasyonlardan ve diğerlerinden bahsedeceğiz.

Okuduğun için teşekkür ederim, bir sonraki yazıda görüşmek üzere.

--

--