Főbb pontok
Easing (simítófüggvény) — egy f(t) matematikai függvény, amely a t ∈ [0,1] idő lineáris lefutását egy nemlineáris animációs értékre képezi le. Ha egy animáció egy objektum pozícióját A-ról B-re változtatja 500 ms alatt, az easing meghatározza, hogy az objektum hogyan mozog e pontok között minden időpillanatban. A lineáris easing (f(t) = t) állandó sebességet jelent — az objektum mechanikusan mozog. A nemlineáris easing — természetes: az objektum gyorsul (ease-in), lassul (ease-out), vagy sima kezdéssel és véggel rendelkezik (ease-in-out).
Az easing függvényeket köbös Bézier görbékkel (Cubic Bézier) írjuk le, ahol az X tengely a normalizált idő, az Y tengely a normalizált előrehaladás. Két kontrollpont (P1, P2) határozza meg a görbe alakját. A standard görbéket a CSS specifikáció rögzíti: 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). Ugyanezek az értékek használatosak a CAMediaTimingFunction-ben iOS-ben és a PathInterpolator-ban Android-ban. A Material Design Motion irányelvek szerint az easing görbéknek meg kell felelniük a kontextusnak: megjelenéshez — ease-out (gyors kezdés), eltűnéshez — ease-in (gyors befejezés).
iOS-ben az easinggel való fő munka a CAMediaTimingFunction osztályon keresztül történik a Core Animation-ből. Ez egy köbös Bézier görbét fogad két kontrollpont (c1x, c1y, c2x, c2y) formájában, és alkalmazza a CAAnimation-re (CABasicAnimation, CAKeyframeAnimation). A CAMediaTimingFunction 5 előre definiált függvényt támogat: linear, easeIn, easeOut, easeInEaseOut és default (az easeInEaseOut megfelelője).
A CAMediaTimingFunction a CALayer szintjén működik — az animáció egy külön folyamatban, a render server-ben fut, ami 60fps-t garantál még összetett transzformációk esetén is. Az UIView tulajdonságok (frame, alpha, transform) animálásához az UIKit a UIView.animate-et használja az options: .curveEaseInOut paraméterrel, ami belsőleg szintén létrehoz egy CAMediaTimingFunction-t a megfelelő görbével. iOS 17+-ban hozzáadták a UIViewAnimationCurve.custom-t BlockParameters-szel az egyéni Bézierhez — ez kiküszöböli a saját CAAnimation írásának szükségességét. A CAMediaTimingFunction az UIKit Dynamics-ben és UIScrollView-ben is használatos a lassításhoz (UIScrollViewDecelerationRate).
SwiftUI-ban az easing a Animation struktúrán keresztül van definiálva .easeIn, .easeOut, .easeInOut, .spring és .interpolatingSpring módosítókkal. Ellentétben az UIKit-kel, ahol az animáció procedurális (beginAnimations/commitAnimations), a SwiftUI deklaratív megközelítést használ: az animáció egy állapot tulajdonság, amely változik, és a keretrendszer maga határozza meg, hogyan animálja az átmenetet.
A .timingCurve(c0x, c0y, c1x, c1y) módosító közvetlenül fogadja a köbös Bézier kontrollpontjait — ez a CAMediaTimingFunction teljes megfelelője. A SwiftUI Animation támogatja az előre definiált görbéket statikus tulajdonságként: az Animation.easeInOut megfelel az ease-in-out (0.42, 0.0, 0.58, 1.0) görbének. Rugó animációhoz az Animation.spring(response:dampingFraction:blendDuration) használatos, ahol a dampingFraction < 1 csillapításos rugóhatást hoz létre. A WWDC 2023-ban az Apple bemutatta az Animation.keyframes-t — képkockánkénti animációt egyéni easinggel minden kulcskockán, ami teljes kontrollt biztosít a pálya felett.
Android-ban az easing a PathInterpolator (API 21+) osztályon keresztül van implementálva — ez egy Path objektumot fogad köbös Bézier görbével. A kontrollpontok a Path.cubicTo(x1, y1, x2, y2, x3, y3) segítségével vannak meghatározva, ahol (x1,y1) az első kontrollpont, (x2,y2) a második, (x3,y3) a végpont (mindig 1,1). A PathInterpolator kötelező, ha egyéni görbére van szükség; standard forgatókönyvekhez az AccelerateDecelerateInterpolator (ease-in-out), AccelerateInterpolator (ease-in) és DecelerateInterpolator (ease-out) áll rendelkezésre.
A Jetpack Compose-ban az easing az Easing objektumon keresztül van definiálva az androidx.compose.animation csomagból. Elérhető a FastOutSlowInEasing, LinearOutSlowInEasing, FastOutLinearInEasing, valamint egyéni Easing a CubicBezierEasing segítségével. A Compose Easing az animate*AsState, AnimatedVisibility és AnimatedContent függvényekben alkalmazható. A legfontosabb különbség a View rendszerhez képest: a Compose az easinget a Kotlin oldalon interpolálja (nem a RenderNode-ban), ami nagyobb rugalmasságot biztosít az egyéni animációkhoz, de optimalizálást igényel 120Hz-es kijelzőkön.
Alap animáció a réteg pozíciójához egyéni ease-in-out görbével. A CAMediaTimingFunction a köbös Bézier kontrollpontjait fogadja, amelyek a mozgás sima kezdetét és végét határozzák meg.
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")
}
A (0.42, 0.0, 0.58, 1.0) kontrollpontok a standard ease-in-out görbét határozzák meg. A SwiftUI ugyanezeket a pontokat használja az Animation.easeInOut-hoz. Az ease-in-hez használja a (0.42, 0.0, 1.0, 1.0), az ease-out-hoz — a (0.0, 0.0, 0.58, 1.0) pontokat. A Core Animation a render server-ben hajtja végre az animációt 60/120 fps frekvenciával.
Deklaratív animáció SwiftUI-ban egyéni görbével és rugóhatással. Az animation módosító az isAnimated változásához van kötve.
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()
}
}
}
}
A .timingCurve(c0x, c0y, c1x, c1y, duration) módosító egyéni easing animációt hoz létre SwiftUI-ban. A value paraméter az animációt egy adott állapothoz köti — az isAnimated változásakor a SwiftUI automatikusan alkalmazza a görbét. Rugó animációhoz a timingCurve helyett használja a .spring(response: 0.4, dampingFraction: 0.6) függvényt.
Az ease-in-out megfelelője Android-ban PathInterpolator segítségével. A (0.42, 0.0, 0.58, 1.0) kontrollpontok ugyanazt a görbét határozzák meg, mint iOS-ben.
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()
}
}
A PathInterpolator a (0.42, 0.0, 0.58, 1.0) kontrollpontokkal megegyezik a CAMediaTimingFunction ease-in-out-val iOS-ben. Platformokon átívelő projektekhez használja ugyanazokat a kontrollpontokat — ez garantálja a vizuálisan azonos animációs viselkedést. A Material Design a FastOutSlowInInterpolator (0.4, 0.0, 0.2, 1.0) ajánlja alternatívaként Android-specifikus felületekhez.
Compose-ban az easing a CubicBezierEasing segítségével van definiálva ugyanazokkal a kontrollpontokkal. Az eredmény — egy elem sima megjelenése átlátszósággal és elmozdulással.
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)
)
}
}
A CubicBezierEasing Compose-ban ugyanazt a 4 kontrollpont paramétert fogadja. Az animateFloatAsState automatikusan interpolálja az alpha értéket a megadott görbével. Összehasonlításképpen: a FastOutSlowInEasing Compose-ban megfelel a (0.4, 0.0, 0.2, 1.0) görbének — a Material Design 3 standard görbéjének. Az egyéni görbék a CubicBezierEasing segítségével teljes kontrollt biztosítanak a márka animációkhoz.
Gyakran ismételt kérdések
Az Easing — a simítófüggvény általános fogalma, használatos iOS-ben (CAMediaTimingFunction), weben (CSS ease-in-out) és designban. Az Interpolator — ennek a koncepciónak a megvalósítása Android-ban (TimeInterpolator). Lényegében ugyanaz — az animáció sebességének matematikai görbéje. A különbség csak a névben és a platform API-jában van. Platformokon átívelő projektekben az easing kifejezés univerzálisan használatos.
Az iOS a CAMediaTimingFunction-t biztosítja 5 előre definiált függvénnyel: linear, easeIn, easeOut, easeInEaseOut és custom (köbös Bézier). SwiftUI-ban elérhetők a Animation.easeIn, Animation.easeOut, Animation.easeInOut, Animation.spring és Animation.interpolatingSpring. Egyéni görbékhez használja az Animation.timingCurve(c0x, c0y, c1x, c1y, duration:) függvényt.
Igen, ha ugyanazt a köbös Bézier görbét állítja be. A CAMediaTimingFunction iOS-ben és a PathInterpolator Android-ban elfogadják a köbös Bézier kontrollpontjait (x1, y1, x2, y2). Például az ease-in-out (0.42, 0.0, 0.58, 1.0) görbe azonos viselkedést fog mutatni mindkét platformon. A Material Design ezt a megközelítést használja platformokon átívelő animációkhoz.
Használja a Material Design Motion irányelveit: elemek megjelenéséhez — ease-out (gyors kezdés, sima befejezés), eltűnéséhez — ease-in (gyors befejezés), képernyők közötti mozgáshoz — ease-in-out. Használjon rugó animációt interaktív elemekhez (gombok, kártyák). Kerülje a linear-t — természetellenesnek tűnik.
A rángatózás (jank) akkor fordul elő, amikor az animáció nem éri el a 60fps-t. Ellenőrizze: használja-e a CAMediaTimingFunction-t (nem timert) iOS-ben, PathInterpolator-t (nem Handler.post-t) Android-ban. A fő szálon végzett nehéz számítások, összetett réteghierarchia vagy nagy drawable képkocka kihagyást okozhat. iOS-ben használja a Core Animation-t shouldRasterize-val összetett rétegekhez; Android-ban — Hardware Acceleration-t és GPU renderinget.
Összefoglalás
Kulcsrakész mobilalkalmazást fejlesztünk
Az IT Sectr 2017 óta készít iOS és Android alkalmazásokat induló vállalkozásoknak és vállalkozásoknak. Tanácsot adunk, és a legjobb megoldást javasoljuk.
Olvassa el is