Principalele concluzii
Easing (funcția de netezire) — o funcție matematică f(t) care mapează progresul liniar al timpului t ∈ [0,1] la o valoare neliniară a animației. Dacă animația modifică poziția unui obiect de la A la B în 500 ms, easing determină modul în care obiectul se mișcă între aceste puncte în fiecare moment de timp. Easing liniar (f(t) = t) înseamnă viteză constantă — obiectul se mișcă mecanic. Easing neliniar — natural: obiectul accelerează (ease-in), încetinește (ease-out) sau are un început și sfârșit lin (ease-in-out).
Funcțiile de easing sunt descrise prin curbe Bézier cubice (Cubic Bézier), unde axa X este timpul normalizat, iar axa Y este progresul normalizat. Două puncte de control (P1, P2) determină forma curbei. Curbele standard sunt fixate de specificația CSS: 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). Aceleași valori sunt utilizate în CAMediaTimingFunction în iOS și PathInterpolator în Android. Conform ghidurilor Material Design Motion, curbele de easing trebuie să corespundă contextului: pentru apariție — ease-out (start rapid), pentru dispariție — ease-in (final rapid).
În iOS, lucrul principal cu easing se face prin clasa CAMediaTimingFunction din Core Animation. Aceasta primește o curbă Bézier cubică sub forma a două puncte de control (c1x, c1y, c2x, c2y) și se aplică la CAAnimation (CABasicAnimation, CAKeyframeAnimation). CAMediaTimingFunction suportă 5 funcții predefinite: linear, easeIn, easeOut, easeInEaseOut și default (echivalentul easeInEaseOut).
CAMediaTimingFunction funcționează la nivelul CALayer — animația este executată într-un proces separat, render server, ceea ce garantează 60fps chiar și la transformări complexe. Pentru animația proprietăților UIView (frame, alpha, transform), UIKit utilizează UIView.animate cu parametrul options: .curveEaseInOut, care intern creează și el CAMediaTimingFunction cu curba corespunzătoare. În iOS 17+ a fost adăugat UIViewAnimationCurve.custom cu BlockParameters pentru Bézier personalizat — aceasta elimină necesitatea de a scrie propria CAAnimation. CAMediaTimingFunction este, de asemenea, utilizată în UIKit Dynamics și UIScrollView pentru decelerare (UIScrollViewDecelerationRate).
În SwiftUI, easing este definit prin structura Animation cu modificatorii .easeIn, .easeOut, .easeInOut, .spring și .interpolatingSpring. Spre deosebire de UIKit, unde animația este procedurală (beginAnimations/commitAnimations), SwiftUI utilizează o abordare declarativă: animația este o proprietate de stare care se modifică, iar framework-ul determină singur cum să animeze tranziția.
Modificatorul .timingCurve(c0x, c0y, c1x, c1y) primește direct punctele de control ale Bézier-ului cubic — este analogul complet al CAMediaTimingFunction. SwiftUI Animation suportă curbele predefinite ca proprietăți statice: Animation.easeInOut este echivalent cu ease-in-out (0.42, 0.0, 0.58, 1.0). Pentru animația cu arc se utilizează Animation.spring(response:dampingFraction:blendDuration), unde dampingFraction < 1 creează un efect de arc cu amortizare. La WWDC 2023, Apple a prezentat Animation.keyframes — animație cadru cu cadru cu easing personalizat pe fiecare cadru cheie, oferind control complet asupra traiectoriei.
În Android, easing este implementat prin PathInterpolator (API 21+) — o clasă care primește un obiect Path cu o curbă Bézier cubică. Punctele de control sunt definite prin Path.cubicTo(x1, y1, x2, y2, x3, y3), unde (x1,y1) este primul punct de control, (x2,y2) al doilea, (x3,y3) punctul final (întotdeauna 1,1). PathInterpolator este obligatoriu dacă este necesară o curbă personalizată; pentru scenarii standard sunt disponibile AccelerateDecelerateInterpolator (ease-in-out), AccelerateInterpolator (ease-in) și DecelerateInterpolator (ease-out).
În Jetpack Compose, easing este definit prin obiectul Easing din pachetul androidx.compose.animation. Sunt disponibile FastOutSlowInEasing, LinearOutSlowInEasing, FastOutLinearInEasing, precum și Easing personalizat prin CubicBezierEasing. Compose Easing se aplică în animate*AsState, AnimatedVisibility și AnimatedContent. Diferența cheie față de sistemul View: Compose interpolează easing pe partea Kotlin (nu în RenderNode), ceea ce oferă mai multă flexibilitate pentru animații personalizate, dar necesită optimizare la display-urile de 120Hz.
Animația de bază a poziției stratului cu o curbă personalizată ease-in-out. CAMediaTimingFunction primește punctele de control ale Bézier-ului cubic, definind un început și un sfârșit lin al mișcării.
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")
}
Punctele de control (0.42, 0.0, 0.58, 1.0) definesc curba standard ease-in-out. SwiftUI utilizează aceleași puncte pentru Animation.easeInOut. Pentru ease-in utilizați (0.42, 0.0, 1.0, 1.0), pentru ease-out — (0.0, 0.0, 0.58, 1.0). Core Animation execută animația în render server cu o frecvență de 60/120 fps.
Animația declarativă în SwiftUI cu o curbă personalizată și efect de arc. Modificatorul animation este legat de modificarea isAnimated.
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()
}
}
}
}
Modificatorul .timingCurve(c0x, c0y, c1x, c1y, duration) creează o animație easing personalizată în SwiftUI. Parametrul value leagă animația de o anumită stare — la modificarea isAnimated, SwiftUI aplică automat curba. Pentru animația cu arc, utilizați .spring(response: 0.4, dampingFraction: 0.6) în loc de timingCurve.
Echivalentul ease-in-out în Android prin PathInterpolator. Punctele de control (0.42, 0.0, 0.58, 1.0) definesc aceeași curbă ca în iOS.
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()
}
}
PathInterpolator cu punctele de control (0.42, 0.0, 0.58, 1.0) este identic cu CAMediaTimingFunction ease-in-out pe iOS. Pentru proiecte cross-platform, utilizați aceleași puncte de control — aceasta garantează un comportament vizual identic al animației. Material Design recomandă FastOutSlowInInterpolator (0.4, 0.0, 0.2, 1.0) ca alternativă pentru interfețe specifice Android.
În Compose, easing este definit prin CubicBezierEasing cu aceleași puncte de control. Rezultatul — o apariție lină a elementului cu transparență și deplasare.
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)
)
}
}
CubicBezierEasing în Compose primește aceiași 4 parametri ai punctelor de control. animateFloatAsState interpolează automat valoarea alpha cu curba dată. Pentru comparație: FastOutSlowInEasing în Compose este echivalent cu (0.4, 0.0, 0.2, 1.0) — curba standard Material Design 3. Curbele personalizate prin CubicBezierEasing oferă control complet pentru animații de brand.
Întrebări frecvente
Easing — conceptul general al funcției de netezire, utilizat în iOS (CAMediaTimingFunction), web (CSS ease-in-out) și design. Interpolator — implementarea acestui concept în Android (TimeInterpolator). În esență, sunt același lucru — o curbă matematică a vitezei de animație. Diferența constă doar în denumire și API-ul platformei. În proiectele cross-platform, termenul easing este utilizat ca unul universal.
iOS oferă CAMediaTimingFunction cu 5 funcții predefinite: linear, easeIn, easeOut, easeInEaseOut și custom (Bézier cubic). În SwiftUI sunt disponibile Animation.easeIn, Animation.easeOut, Animation.easeInOut, Animation.spring și Animation.interpolatingSpring. Pentru curbe personalizate, utilizați Animation.timingCurve(c0x, c0y, c1x, c1y, duration:).
Da, dacă setați aceeași curbă Bézier cubică. CAMediaTimingFunction în iOS și PathInterpolator în Android acceptă punctele de control ale Bézier-ului cubic (x1, y1, x2, y2). De exemplu, curba ease-in-out (0.42, 0.0, 0.58, 1.0) va avea același comportament pe ambele platforme. Material Design utilizează această abordare pentru animații cross-platform.
Utilizați ghidurile Material Design Motion: pentru apariția elementelor — ease-out (start rapid, final lin), pentru dispariție — ease-in (final rapid), pentru deplasarea între ecrane — ease-in-out. Utilizați animația cu arc pentru elemente interactive (butoane, carduri). Evitați linear — arată nenatural.
Sacadarea (jank) apare atunci când animația nu atinge 60fps. Verificați: dacă utilizați CAMediaTimingFunction (nu timer) în iOS, PathInterpolator (nu Handler.post) în Android. Calculele grele pe firul principal, ierarhia complexă a straturilor sau un drawable mare pot cauza pierderi de cadre. În iOS, utilizați Core Animation cu shouldRasterize pentru straturi complexe; în Android — Hardware Acceleration și GPU rendering.
Rezumat
Vom dezvolta o aplicație mobilă la cheie
IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.
Citiți și