Anahtar Noktalar
Easing (yumuşatma fonksiyonu), doğrusal zaman t ∈ [0,1]'i doğrusal olmayan bir animasyon değerine eşleyen matematiksel bir f(t) fonksiyonudur. Bir animasyon 500 ms'de bir nesnenin konumunu A'dan B'ye değiştiriyorsa, easing nesnenin zamanın her anında bu noktalar arasında nasıl hareket ettiğini belirler. Doğrusal easing (f(t) = t) sabit hız anlamına gelir — nesne mekanik olarak hareket eder. Doğrusal olmayan easing doğaldır: nesne hızlanır (ease-in), yavaşlar (ease-out) veya pürüzsüz bir başlangıç ve bitişe sahiptir (ease-in-out).
Easing fonksiyonları, X ekseninin normalize edilmiş zaman ve Y ekseninin normalize edilmiş ilerleme olduğu kübik Bézier eğrileriyle tanımlanır. İki kontrol noktası (P1, P2) eğri şeklini belirler. Standart eğriler CSS şartnamesi tarafından sabitlenmiştir: ease (0.25, 0.1, 0.25, 1.0), ease-in (0.42, 0.0, 1.0, 1.0), ease-out (0.0, 0.0, 0.58, 1.0), ease-in-out (0.42, 0.0, 0.58, 1.0). Bu aynı değerler iOS'ta CAMediaTimingFunction ve Android'de PathInterpolator'da kullanılır. Material Design Hareket Yönergeleri'ne göre, easing eğrileri bağlama uygun olmalıdır: görünme için — ease-out (hızlı başlangıç), kaybolma için — ease-in (hızlı bitiş).
iOS'ta easing esas olarak Core Animation'daki CAMediaTimingFunction sınıfı aracılığıyla çalışır. İki kontrol noktası (c1x, c1y, c2x, c2y) olarak kübik bir Bézier eğrisi kabul eder ve CAAnimation'a (CABasicAnimation, CAKeyframeAnimation) uygulanır. CAMediaTimingFunction 5 ön tanımlı fonksiyonu destekler: linear, easeIn, easeOut, easeInEaseOut ve default (easeInEaseOut'a eşdeğer).
CAMediaTimingFunction CALayer düzeyinde çalışır — animasyon, karmaşık dönüşümlerde bile 60fps'yi garanti eden ayrı bir işleme sunucusu sürecinde çalışır. UIView özelliklerinin (frame, alpha, transform) animasyonu için UIKit, options parametresi .curveEaseInOut ile UIView.animate'i kullanır ve bu da dahili olarak ilgili eğriyle bir CAMediaTimingFunction oluşturur. iOS 17+'da, özel Bézier için UIViewAnimationCurve.custom, BlockParameters ile eklendi — bu, özel CAAnimation yazma ihtiyacını ortadan kaldırır. CAMediaTimingFunction, UIKit Dynamics ve UIScrollView'de yavaşlama (UIScrollViewDecelerationRate) için de kullanılır.
SwiftUI'da easing, .easeIn, .easeOut, .easeInOut, .spring ve .interpolatingSpring değiştiricileriyle Animation yapısı aracılığıyla ayarlanır. Animasyonun prosedürel (beginAnimations/commitAnimations) olduğu UIKit'in aksine, SwiftUI bildirimsel bir yaklaşım kullanır: animasyon değişen bir durum özelliğidir ve çerçeve, geçişi nasıl canlandıracağını kendisi belirler.
.timingCurve(c0x, c0y, c1x, c1y) değiştiricisi, kübik Bézier kontrol noktalarını doğrudan kabul eder — bu, CAMediaTimingFunction'ın tam bir benzeridir. SwiftUI Animation, ön tanımlı eğrileri statik özellikler olarak destekler: Animation.easeInOut, ease-in-out (0.42, 0.0, 0.58, 1.0) ile eşdeğerdir. Yay animasyonu için, dampingFraction < 1'in sönümlemeli bir yay etkisi yarattığı Animation.spring(response:dampingFraction:blendDuration) kullanılır. WWDC 2023'te Apple, her ana karede özel easing ile kare kare animasyon sağlayan ve yörünge üzerinde tam kontrol veren Animation.keyframes'i tanıttı.
Android'de easing, kübik Bézier eğrisine sahip bir Path nesnesini kabul eden PathInterpolator (API 21+) aracılığıyla uygulanır. Kontrol noktaları, Path.cubicTo(x1, y1, x2, y2, x3, y3) aracılığıyla belirtilir; burada (x1,y1) ilk kontrol noktası, (x2,y2) ikinci ve (x3,y3) bitiş noktasıdır (her zaman 1,1). Özel bir eğri gerekiyorsa PathInterpolator zorunludur; standart senaryolar için AccelerateDecelerateInterpolator (ease-in-out), AccelerateInterpolator (ease-in) ve DecelerateInterpolator (ease-out) mevcuttur.
Jetpack Compose'da easing, androidx.compose.animation paketindeki Easing nesnesi aracılığıyla ayarlanır. FastOutSlowInEasing, LinearOutSlowInEasing, FastOutLinearInEasing ve CubicBezierEasing aracılığıyla özel Easing mevcuttur. Compose Easing, animate*AsState, AnimatedVisibility ve AnimatedContent'te uygulanır. View sisteminden temel fark: Compose, easing'i Kotlin tarafında enterpole eder (RenderNode'da değil), bu da özel animasyonlar için daha fazla esneklik sağlar ancak 120Hz ekranlarda optimizasyon gerektirir.
Özel bir ease-in-out eğrisiyle temel katman konum animasyonu. CAMediaTimingFunction, hareketin pürüzsüz başlangıcını ve bitişini tanımlayan kübik Bézier kontrol noktalarını kabul eder.
import UIKit
func animateLayerPosition() {
let animation = CABasicAnimation(keyPath: "position")
animation.fromValue = CGPoint(x: 0, y: 0)
animation.toValue = CGPoint(x: 300, y: 400)
animation.duration = 0.8
let easing = CAMediaTimingFunction(
controlPoints: 0.42, 0.0, 0.58, 1.0
)
animation.timingFunction = easing
animation.fillMode = .forwards
animation.isRemovedOnCompletion = false
layer.add(animation, forKey: "positionAnimation")
}
Kontrol noktaları (0.42, 0.0, 0.58, 1.0) standart ease-in-out eğrisini tanımlar. SwiftUI, Animation.easeInOut için aynı noktaları kullanır. Ease-in için (0.42, 0.0, 1.0, 1.0); ease-out için — (0.0, 0.0, 0.58, 1.0) kullanın. Core Animation, animasyonu işleme sunucusunda 60/120 fps'de yürütür.
Özel bir eğri ve yay etkisiyle SwiftUI'da bildirimsel animasyon. Animasyon değiştiricisi, isAnimated değişikliğine bağlanır.
import SwiftUI
struct EasingExampleView: View {
@State private var isAnimated = false
var body: some View {
VStack {
Circle()
.fill(Color.blue)
.frame(width: 60, height: 60)
.offset(x: isAnimated ? 100 : 0, y: 0)
.animation(
.timingCurve(0.42, 0.0, 0.58, 1.0, duration: 0.6),
value: isAnimated
)
Button("Toggle") {
isAnimated.toggle()
}
}
}
}
.timingCurve(c0x, c0y, c1x, c1y, duration) değiştiricisi, SwiftUI'da özel bir easing animasyonu oluşturur. value parametresi, animasyonu belirli bir duruma bağlar — isAnimated değiştiğinde, SwiftUI otomatik olarak eğriyi uygular. Yay animasyonu için timingCurve yerine .spring(response: 0.4, dampingFraction: 0.6) kullanın.
PathInterpolator aracılığıyla Android'de ease-in-out eşdeğeri. Kontrol noktaları (0.42, 0.0, 0.58, 1.0), iOS'takiyle aynı eğriyi tanımlar.
import android.animation.ObjectAnimator
import android.graphics.Path
import android.view.animation.PathInterpolator
import android.view.View
fun View.fadeInWithEase() {
val path = Path().apply {
cubicTo(0.42f, 0.0f, 0.58f, 1.0f, 1.0f, 1.0f)
}
val interpolator = PathInterpolator(path)
ObjectAnimator.ofFloat(this, "alpha", 0f, 1f).apply {
duration = 500
interpolator = interpolator
start()
}
}
Kontrol noktaları (0.42, 0.0, 0.58, 1.0) ile PathInterpolator, iOS'taki CAMediaTimingFunction ease-in-out ile aynıdır. Platformlar arası projeler için aynı kontrol noktalarını kullanın — bu, görsel olarak aynı animasyon davranışını garanti eder. Material Design, Android'e özel arayüzler için alternatif olarak FastOutSlowInInterpolator'u (0.4, 0.0, 0.2, 1.0) önerir.
Compose'da easing, aynı kontrol noktalarıyla CubicBezierEasing aracılığıyla ayarlanır. Sonuç, şeffaflık ve ofset ile pürüzsüz bir öğe görünümüdür.
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.core.CubicBezierEasing
import androidx.compose.animation.core.tween
import androidx.compose.foundation.layout.*
import androidx.compose.material3.*
import androidx.compose.runtime.*
@Composable
fun EasingComposable() {
var visible by remember { mutableStateOf(false) }
val easing = CubicBezierEasing(0.42f, 0.0f, 0.58f, 1.0f)
val alpha by animateFloatAsState(
targetValue = if (visible) 1f else 0f,
animationSpec = tween(durationMillis = 500, easing = easing)
)
Column {
Button(onClick = { visible = !visible }) {
Text("Toggle")
}
Box(
modifier = Modifier
.size(100.dp)
.graphicsLayer(alpha = alpha)
.background(MaterialTheme.colorScheme.primary)
)
}
}
Compose'da CubicBezierEasing aynı 4 kontrol noktası parametresini kabul eder. animateFloatAsState, belirtilen eğriyle alpha değerini otomatik olarak enterpole eder. Karşılaştırma için: Compose'da FastOutSlowInEasing, (0.4, 0.0, 0.2, 1.0) — standart Material Design 3 eğrisi — ile eşdeğerdir. CubicBezierEasing aracılığıyla özel eğriler, marka animasyonları için tam kontrol sağlar.
Sıkça Sorulan Sorular
Easing, iOS'ta (CAMediaTimingFunction), web'de (CSS ease-in-out) ve tasarımda kullanılan bir yumuşatma fonksiyonunun genel bir kavramıdır. Interpolator, bu kavramın Android'deki (TimeInterpolator) uygulamasıdır. Özünde aynı şeydir — animasyon hızının matematiksel bir eğrisi. Fark yalnızca ad ve platform API'sindedir. Platformlar arası projelerde, easing terimi evrensel olarak kullanılır.
iOS, 5 ön tanımlı fonksiyonla CAMediaTimingFunction sağlar: linear, easeIn, easeOut, easeInEaseOut ve custom (kübik Bézier). SwiftUI'da Animation.easeIn, Animation.easeOut, Animation.easeInOut, Animation.spring ve Animation.interpolatingSpring mevcuttur. Özel eğriler için Animation.timingCurve(c0x, c0y, c1x, c1y, duration:) kullanın.
Evet, aynı kübik Bézier eğrisi ayarlanırsa. iOS'ta CAMediaTimingFunction ve Android'de PathInterpolator, kübik Bézier kontrol noktalarını (x1, y1, x2, y2) kabul eder. Örneğin, ease-in-out (0.42, 0.0, 0.58, 1.0) eğrisi her iki platformda da aynı davranışı gösterecektir. Material Design, platformlar arası animasyonlar için bu yaklaşımı kullanır.
Material Design Hareket Yönergeleri'ni kullanın: öğe görünümü için — ease-out (hızlı başlangıç, pürüzsüz bitiş), kaybolma için — ease-in (hızlı bitiş), ekranlar arası hareket için — ease-in-out. Etkileşimli öğeler (düğmeler, kartlar) için yay animasyonu kullanın. Linear'dan kaçının — doğal görünmez.
Kesiklilik (jank), animasyon 60fps'ye ulaşamadığında oluşur. Şunları kontrol edin: iOS'ta CAMediaTimingFunction (zamanlayıcı değil) kullanıyor musunuz? Android'de PathInterpolator (Handler.post değil) kullanıyor musunuz? Ana iç iplikteki ağır hesaplamalar, karmaşık katman hiyerarşisi veya büyük bir drawable, kare düşüklerine neden olabilir. iOS'ta karmaşık katmanlar için shouldRasterize ile Core Animation kullanın; Android'de — Donanım Hızlandırma ve GPU işleme kullanın.
Özet
Anahtar teslim bir mobil uygulama geliştireceğiz
IT Sectr, 2017'den beri girişimler ve işletmeler için iOS ve Android uygulamaları oluşturmaktadır. Size danışmanlık yapacak ve en iyi çözümü önereceğiz.
Ayrıca okuyun