Easing: podstata, funkce zjemnění v mobilní animaci

Autor: IT Sectr Publikováno: 2026-03-02 Doba čtení: 8 min
Easing (funkce zjemnění) — matematická křivka, která určuje rychlost změny animačního parametru v čase. Místo lineárního rovnoměrně zrychleného pohybu easing napodobuje fyzikální chování: objekt může zrychlovat (ease-in), zpomalovat (ease-out) nebo dělat obojí (ease-in-out). V iOS je easing implementován prostřednictvím třídy CAMediaTimingFunction (Core Animation) a modifikátorů SwiftUI (Animation.easeInOut). V Androidu — prostřednictvím PathInterpolator a TimeInterpolator. Podle dokumentace Apple Developer správně zvolená křivka easingu zkracuje vnímaný čas animace o 20–35 % bez změny skutečné délky. V IT Sectr jsme standardizovali křivku ease-in-out (0.42, 0.0, 0.58, 1.0) jako firemní standard pro všechny mobilní projekty.

Hlavní body

  • Easing — funkce rychlosti animace napodobující fyzický pohyb: zrychlení, zpomalení nebo kombinace.
  • CAMediaTimingFunction — třída iOS Core Animation s 5 předdefinovanými křivkami a vlastní kubickou Bézier.
  • SwiftUI Animation — modifikátory .easeIn, .easeOut, .easeInOut, .spring a .timingCurve pro deklarativní easing.
  • PathInterpolator — analogie easingu v Androidu s kubickou Bézier křivkou přes dva řídicí body.
  • Kubická Bézier — univerzální formát definice křivky easingu, společný pro iOS, Android a web.

Co je Easing?

Easing (funkce zjemnění) — matematická funkce f(t), která mapuje lineární průběh času t ∈ [0,1] na nelineární hodnotu animace. Pokud animace mění polohu objektu z A na B za 500 ms, easing určuje, jak se objekt pohybuje mezi těmito body v každém okamžiku. Lineární easing (f(t) = t) znamená konstantní rychlost — objekt se pohybuje mechanicky. Nelineární easing — přirozeně: objekt zrychluje (ease-in), zpomaluje (ease-out) nebo má hladký začátek a konec (ease-in-out).

Funkce easingu jsou popsány kubickými Bézier křivkami (Cubic Bézier), kde osa X je normalizovaný čas a osa Y je normalizovaný pokrok. Dva řídicí body (P1, P2) určují tvar křivky. Standardní křivky jsou stanoveny specifikací 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). Stejné hodnoty se používají v CAMediaTimingFunction v iOS a PathInterpolator v Androidu. Podle pokynů Material Design Motion by křivky easingu měly odpovídat kontextu: pro zobrazení — ease-out (rychlý start), pro zmizení — ease-in (rychlý konec).

Easing v iOS: CAMediaTimingFunction

V iOS probíhá hlavní práce s easingem prostřednictvím třídy CAMediaTimingFunction z Core Animation. Ta přijímá kubickou Bézier křivku ve formě dvou řídicích bodů (c1x, c1y, c2x, c2y) a aplikuje se na CAAnimation (CABasicAnimation, CAKeyframeAnimation). CAMediaTimingFunction podporuje 5 předdefinovaných funkcí: linear, easeIn, easeOut, easeInEaseOut a default (ekvivalent easeInEaseOut).

CAMediaTimingFunction pracuje na úrovni CALayer — animace je prováděna v samostatném procesu render server, což zaručuje 60fps i při složitých transformacích. Pro animaci vlastností UIView (frame, alpha, transform) UIKit používá UIView.animate s parametrem options: .curveEaseInOut, který interně také vytváří CAMediaTimingFunction s odpovídající křivkou. V iOS 17+ byl přidán UIViewAnimationCurve.custom s BlockParameters pro vlastní Bézier — to eliminuje potřebu psát vlastní CAAnimation. CAMediaTimingFunction se také používá v UIKit Dynamics a UIScrollView pro deceleraci (UIScrollViewDecelerationRate).

Easing ve SwiftUI

Ve SwiftUI je easing definován prostřednictvím struktury Animation s modifikátory .easeIn, .easeOut, .easeInOut, .spring a .interpolatingSpring. Na rozdíl od UIKit, kde je animace procedurální (beginAnimations/commitAnimations), SwiftUI používá deklarativní přístup: animace je vlastnost stavu, která se mění, a framework sám určuje, jak animovat přechod.

Modifikátor .timingCurve(c0x, c0y, c1x, c1y) přijímá přímo řídicí body kubické Bézier — to je úplná analogie CAMediaTimingFunction. SwiftUI Animation podporuje předdefinované křivky jako statické vlastnosti: Animation.easeInOut je ekvivalentní ease-in-out (0.42, 0.0, 0.58, 1.0). Pro pružinovou animaci se používá Animation.spring(response:dampingFraction:blendDuration), kde dampingFraction < 1 vytváří efekt pružiny s tlumením. Na WWDC 2023 Apple představil Animation.keyframes — snímkovou animaci s vlastním easingem na každém klíčovém snímku, což poskytuje úplnou kontrolu nad trajektorií.

Easing v Androidu: PathInterpolator

V Androidu je easing implementován prostřednictvím PathInterpolator (API 21+) — třídy, která přijímá objekt Path s kubickou Bézier křivkou. Řídicí body jsou definovány pomocí Path.cubicTo(x1, y1, x2, y2, x3, y3), kde (x1,y1) je první řídicí bod, (x2,y2) druhý, (x3,y3) koncový bod (vždy 1,1). PathInterpolator je povinný, pokud je potřeba vlastní křivka; pro standardní scénáře jsou k dispozici AccelerateDecelerateInterpolator (ease-in-out), AccelerateInterpolator (ease-in) a DecelerateInterpolator (ease-out).

V Jetpack Compose je easing definován prostřednictvím objektu Easing z balíčku androidx.compose.animation. K dispozici jsou FastOutSlowInEasing, LinearOutSlowInEasing, FastOutLinearInEasing, stejně jako vlastní Easing přes CubicBezierEasing. Compose Easing se aplikuje v animate*AsState, AnimatedVisibility a AnimatedContent. Klíčový rozdíl od systému View: Compose interpoluje easing na straně Kotlin (ne v RenderNode), což poskytuje větší flexibilitu pro vlastní animace, ale vyžaduje optimalizaci na 120Hz displejích.

Příklady kódu

iOS: CAMediaTimingFunction s CABasicAnimation

Základní animace pozice vrstvy s vlastní křivkou ease-in-out. CAMediaTimingFunction přijímá řídicí body kubické Bézier definující hladký začátek a konec pohybu.

swift
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")
}

Řídicí body (0.42, 0.0, 0.58, 1.0) definují standardní křivku ease-in-out. SwiftUI používá stejné body pro Animation.easeInOut. Pro ease-in použijte (0.42, 0.0, 1.0, 1.0), pro ease-out — (0.0, 0.0, 0.58, 1.0). Core Animation provádí animaci v render server s frekvencí 60/120 fps.

SwiftUI: Easing s timingCurve

Deklarativní animace ve SwiftUI s vlastní křivkou a pružinovým efektem. Modifikátor animation je navázán na změnu isAnimated.

swift
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()
            }
        }
    }
}

Modifikátor .timingCurve(c0x, c0y, c1x, c1y, duration) vytváří vlastní easing animaci ve SwiftUI. Parametr value připojuje animaci ke konkrétnímu stavu — při změně isAnimated SwiftUI automaticky aplikuje křivku. Pro pružinovou animaci použijte .spring(response: 0.4, dampingFraction: 0.6) místo timingCurve.

Android: PathInterpolator s vlastním easingem

Ekvivalent ease-in-out v Androidu přes PathInterpolator. Řídicí body (0.42, 0.0, 0.58, 1.0) definují stejnou křivku jako v iOS.

kotlin
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 s řídicími body (0.42, 0.0, 0.58, 1.0) je identický s CAMediaTimingFunction ease-in-out na iOS. Pro multiplatformní projekty používejte stejné řídicí body — to zaručuje vizuálně identické chování animace. Material Design doporučuje FastOutSlowInInterpolator (0.4, 0.0, 0.2, 1.0) jako alternativu pro Android-specifická rozhraní.

Jetpack Compose: Easing s CubicBezierEasing

V Compose je easing definován pomocí CubicBezierEasing se stejnými řídicími body. Výsledek — plynulé zobrazení prvku s průhledností a posunem.

kotlin
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 v Compose přijímá stejné 4 parametry řídicích bodů. animateFloatAsState automaticky interpoluje hodnotu alpha s danou křivkou. Pro srovnání: FastOutSlowInEasing v Compose je ekvivalentní (0.4, 0.0, 0.2, 1.0) — standardní křivka Material Design 3. Vlastní křivky přes CubicBezierEasing poskytují úplnou kontrolu pro značkové animace.

Často kladené otázky

Čím se liší easing od interpolatoru?

Easing — obecný pojem funkce zjemnění, používaný v iOS (CAMediaTimingFunction), webu (CSS ease-in-out) a designu. Interpolator — implementace tohoto konceptu v Androidu (TimeInterpolator). V podstatě je to totéž — matematická křivka rychlosti animace. Rozdíl je pouze v názvu a API platformy. V multiplatformních projektech se termín easing používá jako univerzální.

Jaké easing funkce jsou k dispozici v iOS?

iOS poskytuje CAMediaTimingFunction s 5 předdefinovanými funkcemi: linear, easeIn, easeOut, easeInEaseOut a custom (kubická Bézier). Ve SwiftUI jsou k dispozici Animation.easeIn, Animation.easeOut, Animation.easeInOut, Animation.spring a Animation.interpolatingSpring. Pro vlastní křivky použijte Animation.timingCurve(c0x, c0y, c1x, c1y, duration:).

Mohu použít stejnou easing funkci na iOS a Androidu?

Ano, pokud nastavíte stejnou kubickou Bézier křivku. CAMediaTimingFunction v iOS a PathInterpolator v Androidu přijímají řídicí body kubické Bézier (x1, y1, x2, y2). Například křivka ease-in-out (0.42, 0.0, 0.58, 1.0) bude mít stejné chování na obou platformách. Material Design používá tento přístup pro multiplatformní animace.

Jak vybrat správnou easing křivku pro mou aplikaci?

Použijte pokyny Material Design Motion: pro zobrazování prvků — ease-out (rychlý start, hladký konec), pro mizení — ease-in (rychlý konec), pro přesun mezi obrazovkami — ease-in-out. Použijte pružinovou animaci pro interaktivní prvky (tlačítka, karty). Vyhněte se linear — vypadá nepřirozeně.

Proč moje animace s easingem vypadá trhaně?

Trhání (jank) nastává, když animace nedosahuje 60fps. Zkontrolujte: používáte CAMediaTimingFunction (ne timer) v iOS, PathInterpolator (ne Handler.post) v Androidu. Těžké výpočty v hlavním vlákně, složitá hierarchie vrstev nebo velký drawable mohou způsobovat ztrátu snímků. V iOS použijte Core Animation s shouldRasterize pro složité vrstvy; v Androidu — Hardware Acceleration a GPU rendering.

Shrnutí

  • Easing je funkce rychlosti animace, která činí pohyb přirozeným prostřednictvím nelineární změny parametrů v čase.
  • iOS CAMediaTimingFunction a SwiftUI Animation.timingCurve implementují easing přes kubickou Bézier křivku se dvěma řídicími body.
  • Android PathInterpolator a Compose CubicBezierEasing — úplné analogie iOS pro vlastní křivky zjemnění.
  • Multiplatformní easing křivky jsou definovány identickými řídicími body — základ unifikace animací.
  • Material Design 3 doporučuje fast-out-slow-in pro zobrazení, linear-out-slow-in pro zmizení.
  • Pružinová animace ve SwiftUI (Animation.spring) a Compose (spring()) vytváří fyzický efekt pružiny s dampingFraction.
  • Lineární easing není doporučen pro animace rozhraní — vypadá nepřirozeně a mechanicky.

Vyvineme mobilní aplikaci na klíč

IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.

Prodiskutovat projekt

Přečtěte si také