Easing: essensen, utjämningsfunktioner i mobil animation

Författare: IT Sectr Publicerad: 2026-03-02 Lästid: 8 min
Easing (utjämningsfunktion) — en matematisk kurva som bestämmer hastigheten för förändring av en animationsparameter över tid. Istället för linjär jämnt accelererad rörelse imiterar easing fysiskt beteende: ett objekt kan accelerera (ease-in), sakta ner (ease-out) eller göra båda (ease-in-out). I iOS implementeras easing genom klassen CAMediaTimingFunction (Core Animation) och SwiftUI-modifierare (Animation.easeInOut). I Android — genom PathInterpolator och TimeInterpolator. Enligt Apple Developer-dokumentationen minskar en väl vald easing-kurva den upplevda animationstiden med 20–35 % utan att ändra den faktiska durationen. På IT Sectr har vi standardiserat ease-in-out-kurvan (0.42, 0.0, 0.58, 1.0) som företagsstandard för alla mobila projekt.

Huvudpunkter

  • Easing — hastighetsfunktion för animation som imiterar fysisk rörelse: acceleration, inbromsning eller kombination.
  • CAMediaTimingFunction — iOS Core Animation-klass med 5 fördefinierade kurvor och anpassad kubisk Bézier.
  • SwiftUI Animation — modifierare .easeIn, .easeOut, .easeInOut, .spring och .timingCurve för deklarativ easing.
  • PathInterpolator — motsvarigheten till easing i Android med kubisk Bézier-kurva genom två kontrollpunkter.
  • Kubisk Bézier — det universella formatet för att definiera en easing-kurva, gemensamt för iOS, Android och webb.

Vad är Easing?

Easing (utjämningsfunktion) — en matematisk funktion f(t) som avbildar tidens linjära förlopp t ∈ [0,1] till ett icke-linjärt animationsvärde. Om en animation ändrar ett objekts position från A till B på 500 ms, bestämmer easing hur objektet rör sig mellan dessa punkter vid varje tidpunkt. Linjär easing (f(t) = t) innebär konstant hastighet — objektet rör sig mekaniskt. Icke-linjär easing — naturligt: objektet accelererar (ease-in), saktar ner (ease-out) eller har en mjuk start och slut (ease-in-out).

Easing-funktioner beskrivs med kubiska Bézier-kurvor (Cubic Bézier), där X-axeln är normaliserad tid och Y-axeln är normaliserat framsteg. Två kontrollpunkter (P1, P2) bestämmer kurvans form. Standardkurvor är fastställda av CSS-specifikationen: 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). Samma värden används i CAMediaTimingFunction i iOS och PathInterpolator i Android. Enligt Material Design Motion-riktlinjerna ska easing-kurvor motsvara sammanhanget: för uppdykande — ease-out (snabb start), för försvinnande — ease-in (snabb finish).

Easing i iOS: CAMediaTimingFunction

I iOS sker det huvudsakliga arbetet med easing genom klassen CAMediaTimingFunction från Core Animation. Den tar emot en kubisk Bézier-kurva i form av två kontrollpunkter (c1x, c1y, c2x, c2y) och tillämpas på CAAnimation (CABasicAnimation, CAKeyframeAnimation). CAMediaTimingFunction stöder 5 fördefinierade funktioner: linear, easeIn, easeOut, easeInEaseOut och default (motsvarande easeInEaseOut).

CAMediaTimingFunction fungerar på CALayer-nivå — animationen utförs i en separat process, render server, vilket garanterar 60fps även vid komplexa transformationer. För animation av UIView-egenskaper (frame, alpha, transform) använder UIKit UIView.animate med parametern options: .curveEaseInOut, som internt också skapar en CAMediaTimingFunction med motsvarande kurva. I iOS 17+ har UIViewAnimationCurve.custom med BlockParameters för anpassad Bézier lagts till — detta eliminerar behovet av att skriva en egen CAAnimation. CAMediaTimingFunction används även i UIKit Dynamics och UIScrollView för retardation (UIScrollViewDecelerationRate).

Easing i SwiftUI

I SwiftUI definieras easing genom strukturen Animation med modifierare .easeIn, .easeOut, .easeInOut, .spring och .interpolatingSpring. Till skillnad från UIKit där animation är proceduriell (beginAnimations/commitAnimations) använder SwiftUI ett deklarativt tillvägagångssätt: animation är en tillståndsegenskap som ändras och ramverket bestämmer själv hur övergången ska animeras.

Modifieraren .timingCurve(c0x, c0y, c1x, c1y) tar emot kontrollpunkterna för den kubiska Bézier-kurvan direkt — detta är den fullständiga motsvarigheten till CAMediaTimingFunction. SwiftUI Animation stöder fördefinierade kurvor som statiska egenskaper: Animation.easeInOut motsvarar ease-in-out (0.42, 0.0, 0.58, 1.0). För fjäderanimation används Animation.spring(response:dampingFraction:blendDuration), där dampingFraction < 1 skapar en fjäderverkan med dämpning. På WWDC 2023 introducerade Apple Animation.keyframes — bild-för-bild-animation med anpassad easing på varje nyckelbild, vilket ger fullständig kontroll över banan.

Easing i Android: PathInterpolator

I Android implementeras easing genom PathInterpolator (API 21+) — en klass som tar emot ett Path-objekt med en kubisk Bézier-kurva. Kontrollpunkterna definieras genom Path.cubicTo(x1, y1, x2, y2, x3, y3), där (x1,y1) är första kontrollpunkten, (x2,y2) den andra och (x3,y3) slutpunkten (alltid 1,1). PathInterpolator är obligatorisk om en anpassad kurva behövs; för standardscenarier finns AccelerateDecelerateInterpolator (ease-in-out), AccelerateInterpolator (ease-in) och DecelerateInterpolator (ease-out).

I Jetpack Compose definieras easing genom objektet Easing från paketet androidx.compose.animation. FastOutSlowInEasing, LinearOutSlowInEasing, FastOutLinearInEasing samt anpassad Easing genom CubicBezierEasing finns tillgängliga. Compose Easing tillämpas i animate*AsState, AnimatedVisibility och AnimatedContent. Den viktigaste skillnaden från View-systemet: Compose interpolerar easing på Kotlin-sidan (inte i RenderNode), vilket ger mer flexibilitet för anpassade animationer, men kräver optimering på 120Hz-skärmar.

Kodexempel

iOS: CAMediaTimingFunction med CABasicAnimation

Grundläggande animation av lagerposition med anpassad ease-in-out-kurva. CAMediaTimingFunction tar emot kontrollpunkterna för den kubiska Bézier-kurvan som definierar en mjuk start och slut på rörelsen.

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

Kontrollpunkterna (0.42, 0.0, 0.58, 1.0) definierar standardkurvan ease-in-out. SwiftUI använder samma punkter för Animation.easeInOut. För ease-in använd (0.42, 0.0, 1.0, 1.0), för ease-out — (0.0, 0.0, 0.58, 1.0). Core Animation utför animationen i render server med en frekvens på 60/120 fps.

SwiftUI: Easing med timingCurve

Deklarativ animation i SwiftUI med anpassad kurva och fjäderverkan. Modifieraren animation är kopplad till ändringen av 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()
            }
        }
    }
}

Modifieraren .timingCurve(c0x, c0y, c1x, c1y, duration) skapar en anpassad easing-animation i SwiftUI. Parametern value kopplar animationen till ett specifikt tillstånd — när isAnimated ändras tillämpar SwiftUI automatiskt kurvan. För fjäderanimation, använd .spring(response: 0.4, dampingFraction: 0.6) istället för timingCurve.

Android: PathInterpolator med anpassad easing

Motsvarigheten till ease-in-out i Android genom PathInterpolator. Kontrollpunkterna (0.42, 0.0, 0.58, 1.0) definierar samma kurva som i 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 med kontrollpunkter (0.42, 0.0, 0.58, 1.0) är identisk med CAMediaTimingFunction ease-in-out på iOS. För plattformsoberoende projekt, använd samma kontrollpunkter — detta garanterar visuellt identiskt animationsbeteende. Material Design rekommenderar FastOutSlowInInterpolator (0.4, 0.0, 0.2, 1.0) som ett alternativ för Android-specifika gränssnitt.

Jetpack Compose: Easing med CubicBezierEasing

I Compose definieras easing genom CubicBezierEasing med samma kontrollpunkter. Resultatet — en mjuk uppdykning av ett element med transparens och förskjutning.

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 i Compose tar emot samma 4 parametrar för kontrollpunkter. animateFloatAsState interpolerar automatiskt alfavärdet med den givna kurvan. För jämförelse: FastOutSlowInEasing i Compose motsvarar (0.4, 0.0, 0.2, 1.0) — standardkurvan för Material Design 3. Anpassade kurvor genom CubicBezierEasing ger full kontroll för varumärkesanimationer.

Vanliga frågor

Vad är skillnaden mellan easing och interpolator?

Easing — det allmänna begreppet för utjämningsfunktion, som används i iOS (CAMediaTimingFunction), webben (CSS ease-in-out) och design. Interpolator — implementeringen av detta koncept i Android (TimeInterpolator). I grund och botten är det samma sak — en matematisk kurva för animationshastighet. Skillnaden är bara i namn och plattformens API. I plattformsoberoende projekt används termen easing som universell.

Vilka easing-funktioner finns tillgängliga i iOS?

iOS erbjuder CAMediaTimingFunction med 5 fördefinierade funktioner: linear, easeIn, easeOut, easeInEaseOut och custom (kubisk Bézier). I SwiftUI finns Animation.easeIn, Animation.easeOut, Animation.easeInOut, Animation.spring och Animation.interpolatingSpring. För anpassade kurvor, använd Animation.timingCurve(c0x, c0y, c1x, c1y, duration:).

Kan jag använda samma easing-funktion på iOS och Android?

Ja, om du ställer in samma kubiska Bézier-kurva. CAMediaTimingFunction i iOS och PathInterpolator i Android accepterar kontrollpunkterna för kubisk Bézier (x1, y1, x2, y2). Till exempel kommer kurvan ease-in-out (0.42, 0.0, 0.58, 1.0) att ge identiskt beteende på båda plattformarna. Material Design använder detta tillvägagångssätt för plattformsoberoende animationer.

Hur väljer jag rätt easing-kurva för min applikation?

Använd Material Design Motion-riktlinjerna: för uppdykande av element — ease-out (snabb start, mjuk finish), för försvinnande — ease-in (snabb finish), för förflyttning mellan skärmar — ease-in-out. Använd fjäderanimation för interaktiva element (knappar, kort). Undvik linear — det ser onaturligt ut.

Varför ser min animation med easing ryckig ut?

Ryckighet (jank) uppstår när animationen inte når 60fps. Kontrollera: använder du CAMediaTimingFunction (inte timer) i iOS, PathInterpolator (inte Handler.post) i Android. Tunga beräkningar i huvudtråden, komplex lagerhierarki eller stor drawable kan orsaka bildbortfall. I iOS, använd Core Animation med shouldRasterize för komplexa lager; i Android — Hardware Acceleration och GPU-rendering.

Sammanfattning

  • Easing är hastighetsfunktionen för animation som gör rörelse naturlig genom icke-linjär förändring av parametrar över tid.
  • iOS CAMediaTimingFunction och SwiftUI Animation.timingCurve implementerar easing genom kubisk Bézier-kurva med två kontrollpunkter.
  • Android PathInterpolator och Compose CubicBezierEasing — fullständiga motsvarigheter till iOS för anpassade utjämningskurvor.
  • Plattformsoberoende easing-kurvor definieras med identiska kontrollpunkter — grunden för enhetliggörande av animationer.
  • Material Design 3 rekommenderar fast-out-slow-in för uppdykande, linear-out-slow-in för försvinnande.
  • Fjäderanimation i SwiftUI (Animation.spring) och Compose (spring()) skapar en fysisk fjäderverkan med dampingFraction.
  • Linjär easing rekommenderas inte för gränssnittsanimationer — det ser onaturligt och mekaniskt ut.

Vi utvecklar en mobil applikation nyckelfärdigt

IT Sectr skapar iOS- och Android-applikationer för startups och företag sedan 2017. Vi ger dig råd och föreslår den bästa lösningen.

Diskutera projektet

Läs också