Jetpack Compose İle Animasyon I
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.
Ü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:
ExitTransition:
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ğeriniEnterTransition.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 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.
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.
Kaynakça: