Easing: суштина, функције заглађивања у мобилној анимацији

Аутор: IT Sectr Објављено: 2026-03-02 Време читања: 8 мин
Easing (функција заглађивања) — математичка крива која одређује брзину промене анимационог параметра током времена. Уместо линеарног равномерно убрзаног кретања, easing имитира физичко понашање: објекат може да убрзава (ease-in), успорава (ease-out) или да ради и једно и друго (ease-in-out). У iOS-у easing је имплементиран кроз класу CAMediaTimingFunction (Core Animation) и модификаторе SwiftUI (Animation.easeInOut). У Android-у — кроз PathInterpolator и TimeInterpolator. Према Apple Developer документацији, правилно одабрана easing крива смањује перципирано време анимације за 20–35% без промене стварног трајања. У IT Sectr-у смо стандардизовали криву ease-in-out (0.42, 0.0, 0.58, 1.0) као корпоративни стандард за све мобилне пројекте.

Главни закључци

  • Easing — функција брзине анимације која имитира физичко кретање: убрзање, успоравање или комбинацију.
  • CAMediaTimingFunction — класа iOS Core Animation са 5 предефинисаних крива и прилагођеном кубичном Безјеовом кривом.
  • SwiftUI Animation — модификатори .easeIn, .easeOut, .easeInOut, .spring и .timingCurve за декларативни easing.
  • PathInterpolator — аналог easing-а у Android-у са кубичном Безјеовом кривом кроз две контролне тачке.
  • Кубична Безјеова крива — универзални формат задавања easing криве, заједнички за iOS, Android и веб.

Шта је Easing?

Easing (функција заглађивања) — математичка функција f(t) која пресликава линеарни ток времена t ∈ [0,1] у нелинеарну вредност анимације. Ако анимација мења положај објекта од A до B за 500 ms, easing одређује како се објекат креће између ових тачака у сваком тренутку времена. Линеарни easing (f(t) = t) значи константну брзину — објекат се креће механички. Нелинеарни easing — природно: објекат убрзава (ease-in), успорава (ease-out) или има гладак почетак и крај (ease-in-out).

Easing функције се описују кубичним Безјеовим кривама (Cubic Bézier), где је X оса нормализовано време, а Y оса нормализовани напредак. Две контролне тачке (P1, P2) одређују облик криве. Стандардне криве су фиксиране 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). Исте вредности се користе у CAMediaTimingFunction у iOS-у и PathInterpolator у Android-у. Према Material Design Motion смерницама, easing криве треба да одговарају контексту: за појављивање — ease-out (брз старт), за нестајање — ease-in (брз финиш).

Easing у iOS-у: CAMediaTimingFunction

У iOS-у главни рад са easing-ом се обавља кроз класу CAMediaTimingFunction из Core Animation-а. Она прима кубичну Безјеову криву у облику две контролне тачке (c1x, c1y, c2x, c2y) и примењује се на CAAnimation (CABasicAnimation, CAKeyframeAnimation). CAMediaTimingFunction подржава 5 предефинисаних функција: linear, easeIn, easeOut, easeInEaseOut и default (еквивалент easeInEaseOut).

CAMediaTimingFunction ради на нивоу CALayer-а — анимација се извршава у одвојеном процесу render server-а, што гарантује 60fps чак и при сложеним трансформацијама. За анимацију својстава UIView (frame, alpha, transform), UIKit користи UIView.animate са параметром options: .curveEaseInOut, који унутрашњи такође креира CAMediaTimingFunction са одговарајућом кривом. У iOS 17+ додат је UIViewAnimationCurve.custom са BlockParameters за прилагођену Безјеову криву — ово елиминише потребу за писањем сопствене CAAnimation. CAMediaTimingFunction се такође користи у UIKit Dynamics и UIScrollView за декелерацију (UIScrollViewDecelerationRate).

Easing у SwiftUI

У SwiftUI-ју easing се задаје кроз структуру Animation са модификаторима .easeIn, .easeOut, .easeInOut, .spring и .interpolatingSpring. За разлику од UIKit-а, где је анимација процедурална (beginAnimations/commitAnimations), SwiftUI користи декларативни приступ: анимација је својство стања које се мења, а фрејмворк сам одређује како да анимира прелаз.

Модификатор .timingCurve(c0x, c0y, c1x, c1y) директно прима контролне тачке кубичне Безјеове криве — ово је потпуни аналог CAMediaTimingFunction-а. SwiftUI Animation подржава предефинисане криве као статичка својства: Animation.easeInOut је еквивалент ease-in-out (0.42, 0.0, 0.58, 1.0). За spring анимацију користи се Animation.spring(response:dampingFraction:blendDuration), где dampingFraction < 1 ствара ефекат опруге са пригушењем. На WWDC 2023, Apple је представио Animation.keyframes — кадар-по-кадар анимацију са прилагођеним easing-ом на сваком кључном кадру, што даје потпуну контролу над путањом.

Easing у Android-у: PathInterpolator

У Android-у easing је имплементиран кроз PathInterpolator (API 21+) — класу која прима Path објекат са кубичном Безјеовом кривом. Контролне тачке се задају кроз Path.cubicTo(x1, y1, x2, y2, x3, y3), где су (x1,y1) прва контролна тачка, (x2,y2) друга, (x3,y3) крајња тачка (увек 1,1). PathInterpolator је обавезан ако је потребна прилагођена крива; за стандардне сценарије доступни су AccelerateDecelerateInterpolator (ease-in-out), AccelerateInterpolator (ease-in) и DecelerateInterpolator (ease-out).

У Jetpack Compose-у easing се задаје кроз објекат Easing из пакета androidx.compose.animation. Доступни су FastOutSlowInEasing, LinearOutSlowInEasing, FastOutLinearInEasing, као и прилагођени Easing кроз CubicBezierEasing. Compose Easing се примењује у animate*AsState, AnimatedVisibility и AnimatedContent. Кључна разлика од View система: Compose интерполира easing на страни Kotlin-а (не у RenderNode-у), што даје више флексибилности за прилагођене анимације, али захтева оптимизацију на 120Hz дисплејима.

Примери кода

iOS: CAMediaTimingFunction са CABasicAnimation

Основна анимација позиције слоја са прилагођеном кривом ease-in-out. CAMediaTimingFunction прима контролне тачке кубичне Безјеове криве које дефинишу гладак почетак и крај покрета.

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

Контролне тачке (0.42, 0.0, 0.58, 1.0) дефинишу стандардну криву ease-in-out. SwiftUI користи исте тачке за Animation.easeInOut. За ease-in користите (0.42, 0.0, 1.0, 1.0), за ease-out — (0.0, 0.0, 0.58, 1.0). Core Animation извршава анимацију у render server-у са фреквенцијом 60/120 fps.

SwiftUI: Easing са timingCurve

Декларативна анимација у SwiftUI-ју са прилагођеном кривом и spring ефектом. Модификатор animation је повезан са променом 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()
            }
        }
    }
}

Модификатор .timingCurve(c0x, c0y, c1x, c1y, duration) креира прилагођену easing анимацију у SwiftUI-ју. Параметар value повезује анимацију са конкретним стањем — при промени isAnimated, SwiftUI аутоматски примењује криву. За spring анимацију користите .spring(response: 0.4, dampingFraction: 0.6) уместо timingCurve.

Android: PathInterpolator са прилагођеним easing-ом

Еквивалент ease-in-out у Android-у кроз PathInterpolator. Контролне тачке (0.42, 0.0, 0.58, 1.0) дефинишу исту криву као у 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 са контролним тачкама (0.42, 0.0, 0.58, 1.0) је идентичан CAMediaTimingFunction ease-in-out на iOS-у. За међуплатформске пројекте користите исте контролне тачке — ово гарантује визуелно идентично понашање анимације. Material Design препоручује FastOutSlowInInterpolator (0.4, 0.0, 0.2, 1.0) као алтернативу за Android-специфичне интерфејсе.

Jetpack Compose: Easing са CubicBezierEasing

У Compose-у easing се задаје кроз CubicBezierEasing са истим контролним тачкама. Резултат — глатко појављивање елемента са провидношћу и померањем.

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 у Compose-у прима иста 4 параметра контролних тачака. animateFloatAsState аутоматски интерполира вредност alpha са задатом кривом. За поређење: FastOutSlowInEasing у Compose-у је еквивалентан (0.4, 0.0, 0.2, 1.0) — стандардна крива Material Design 3. Прилагођене криве кроз CubicBezierEasing дају потпуну контролу за бренд анимације.

Често постављана питања

По чему се easing разликује од interpolator-а?

Easing — општи појам функције заглађивања, који се користи у iOS-у (CAMediaTimingFunction), вебу (CSS ease-in-out) и дизајну. Interpolator — имплементација овог концепта у Android-у (TimeInterpolator). У суштини, то је иста ствар — математичка крива брзине анимације. Разлика је само у називу и API-ју платформе. У међуплатформским пројектима термин easing се користи као универзалан.

Које easing функције су доступне у iOS-у?

iOS пружа CAMediaTimingFunction са 5 предефинисаних функција: linear, easeIn, easeOut, easeInEaseOut и custom (кубична Безјеова крива). У SwiftUI-ју су доступне Animation.easeIn, Animation.easeOut, Animation.easeInOut, Animation.spring и Animation.interpolatingSpring. За прилагођене криве користите Animation.timingCurve(c0x, c0y, c1x, c1y, duration:).

Могу ли да користим исту easing функцију на iOS и Android-у?

Да, ако поставите исту кубичну Безјеову криву. CAMediaTimingFunction у iOS-у и PathInterpolator у Android-у примају контролне тачке кубичне Безјеове криве (x1, y1, x2, y2). На пример, крива ease-in-out (0.42, 0.0, 0.58, 1.0) ће дати идентично понашање на обе платформе. Material Design користи овај приступ за међуплатформске анимације.

Како да изаберем праву easing криву за моју апликацију?

Користите Material Design Motion смернице: за појављивање елемената — ease-out (брз старт, гладак финиш), за нестајање — ease-in (брз финиш), за кретање између екрана — ease-in-out. Spring анимацију користите за интерактивне елементе (дугмад, картице). Избегавајте linear — изгледа неприродно.

Зашто моја анимација са easing-ом изгледа трзаво?

Трзавост (jank) настаје када анимација не достиже 60fps. Проверите: да ли користите CAMediaTimingFunction (не timer) у iOS-у, PathInterpolator (не Handler.post) у Android-у. Тешка израчунавања у главној нити, сложена хијерархија слојева или велики drawable могу изазвати испуштање кадрова. У iOS-у користите Core Animation са shouldRasterize за сложене слојеве; у Android-у — Hardware Acceleration и GPU rendering.

Резиме

  • Easing — функција брзине анимације која чини кретање природним кроз нелинеарну промену параметара током времена.
  • iOS CAMediaTimingFunction и SwiftUI Animation.timingCurve имплементирају easing кроз кубичну Безјеову криву са две контролне тачке.
  • Android PathInterpolator и Compose CubicBezierEasing — потпуни аналози iOS-а за прилагођене криве заглађивања.
  • Међуплатформске easing криве се задају идентичним контролним тачкама — основа унификације анимација.
  • Material Design 3 препоручује fast-out-slow-in за појављивање, linear-out-slow-in за нестајање.
  • Spring анимација у SwiftUI (Animation.spring) и Compose (spring()) ствара физички ефекат опруге са dampingFraction.
  • Linear easing се не препоручује за интерфејсне анимације — изгледа неприродно и механички.

Развићемо мобилну апликацију под кључ

IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.

Разговарајте о пројекту

Прочитајте такође