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 Documentation, μια σωστά επιλεγμένη καμπύλη easing μειώνει τον αντιληπτό χρόνο κινούμενης εικόνας κατά 20–35% χωρίς αλλαγή της πραγματικής διάρκειας. Στην IT Sectr, τυποποιήσαμε την καμπύλη ease-in-out (0.42, 0.0, 0.58, 1.0) ως εταιρικό πρότυπο για όλα τα κινητά έργα.

Κύρια σημεία

  • Easing — συνάρτηση ταχύτητας κινούμενης εικόνας που μιμείται φυσική κίνηση: επιτάχυνση, επιβράδυνση ή συνδυασμός.
  • CAMediaTimingFunction — κλάση iOS Core Animation με 5 προκαθορισμένες καμπύλες και προσαρμοσμένη κυβική Bézier.
  • SwiftUI Animation — τροποποιητές .easeIn, .easeOut, .easeInOut, .spring και .timingCurve για δηλωτικό easing.
  • PathInterpolator — το ανάλογο του easing στο Android με κυβική καμπύλη Bézier μέσω δύο σημείων ελέγχου.
  • Κυβική Bézier — η καθολική μορφή ορισμού καμπύλης easing, κοινή για iOS, Android και web.

Τι είναι το Easing;

Easing (συνάρτηση εξομάλυνσης) — μια μαθηματική συνάρτηση f(t) που αντιστοιχίζει τη γραμμική πορεία του χρόνου t ∈ [0,1] σε μια μη γραμμική τιμή κινούμενης εικόνας. Εάν μια κινούμενη εικόνα αλλάζει τη θέση ενός αντικειμένου από Α σε Β σε 500 ms, το easing καθορίζει πώς το αντικείμενο κινείται μεταξύ αυτών των σημείων σε κάθε χρονική στιγμή. Γραμμικό easing (f(t) = t) σημαίνει σταθερή ταχύτητα — το αντικείμενο κινείται μηχανικά. Μη γραμμικό easing — φυσικό: το αντικείμενο επιταχύνει (ease-in), επιβραδύνει (ease-out) ή έχει ομαλή αρχή και τέλος (ease-in-out).

Οι συναρτήσεις easing περιγράφονται από κυβικές καμπύλες Bézier (Cubic Bézier), όπου ο άξονας Χ είναι ο κανονικοποιημένος χρόνος και ο άξονας Υ είναι η κανονικοποιημένη πρόοδος. Δύο σημεία ελέγχου (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. Δέχεται μια κυβική καμπύλη Bézier με τη μορφή δύο σημείων ελέγχου (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 για προσαρμοσμένη Bézier — αυτό εξαλείφει την ανάγκη γραφής δικής σας 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) δέχεται απευθείας τα σημεία ελέγχου της κυβικής Bézier — αυτό είναι το πλήρες ανάλογο της CAMediaTimingFunction. Το SwiftUI Animation υποστηρίζει προκαθορισμένες καμπύλες ως στατικές ιδιότητες: το Animation.easeInOut είναι ισοδύναμο του ease-in-out (0.42, 0.0, 0.58, 1.0). Για κινούμενη εικόνα ελατηρίου, χρησιμοποιείται το Animation.spring(response:dampingFraction:blendDuration), όπου dampingFraction < 1 δημιουργεί εφέ ελατηρίου με απόσβεση. Στο WWDC 2023, η Apple παρουσίασε το Animation.keyframes — κινούμενη εικόνα καρέ-καρέ με προσαρμοσμένο easing σε κάθε βασικό καρέ, που δίνει πλήρη έλεγχο της τροχιάς.

Easing στο Android: PathInterpolator

Στο Android, το easing υλοποιείται μέσω του PathInterpolator (API 21+) — μιας κλάσης που δέχεται ένα αντικείμενο Path με κυβική καμπύλη Bézier. Τα σημεία ελέγχου ορίζονται μέσω 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 δέχεται τα σημεία ελέγχου της κυβικής Bézier που ορίζουν ομαλή αρχή και τέλος κίνησης.

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 με προσαρμοσμένη καμπύλη και εφέ ελατηρίου. Ο τροποποιητής 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(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), στο web (CSS ease-in-out) και στο σχεδιασμό. Το Interpolator — η υλοποίηση αυτής της έννοιας στο Android (TimeInterpolator). Στην ουσία είναι το ίδιο πράγμα — μια μαθηματική καμπύλη ταχύτητας κινούμενης εικόνας. Η διαφορά είναι μόνο στο όνομα και το API της πλατφόρμας. Σε έργα μεταξύ πλατφορμών, ο όρος easing χρησιμοποιείται ως καθολικός.

Ποιες συναρτήσεις easing είναι διαθέσιμες στο iOS;

Το iOS παρέχει CAMediaTimingFunction με 5 προκαθορισμένες συναρτήσεις: linear, easeIn, easeOut, easeInEaseOut και custom (κυβική Bézier). Στο SwiftUI είναι διαθέσιμα Animation.easeIn, Animation.easeOut, Animation.easeInOut, Animation.spring και Animation.interpolatingSpring. Για προσαρμοσμένες καμπύλες, χρησιμοποιήστε Animation.timingCurve(c0x, c0y, c1x, c1y, duration:).

Μπορώ να χρησιμοποιήσω την ίδια συνάρτηση easing σε iOS και Android;

Ναι, εάν ορίσετε την ίδια κυβική καμπύλη Bézier. Η CAMediaTimingFunction στο iOS και το PathInterpolator στο Android δέχονται σημεία ελέγχου κυβικής Bézier (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. Χρησιμοποιήστε κινούμενη εικόνα ελατηρίου για διαδραστικά στοιχεία (κουμπιά, κάρτες). Αποφύγετε το linear — φαίνεται αφύσικο.

Γιατί η κινούμενη εικόνα μου με easing φαίνεται τραχιά;

Η τραχύτητα (jank) εμφανίζεται όταν η κινούμενη εικόνα δεν φτάνει τα 60fps. Ελέγξτε: χρησιμοποιείτε CAMediaTimingFunction (όχι χρονοδιακόπτη) στο iOS, PathInterpolator (όχι Handler.post) στο Android. Βαριοί υπολογισμοί στο κύριο νήμα, περίπλοκη ιεραρχία επιπέδων ή μεγάλο drawable μπορεί να προκαλέσουν απώλεια καρέ. Στο iOS, χρησιμοποιήστε Core Animation με shouldRasterize για περίπλοκα επίπεδα· στο Android — Hardware Acceleration και GPU rendering.

Σύνοψη

  • Το Easing είναι συνάρτηση ταχύτητας κινούμενης εικόνας που κάνει την κίνηση φυσική μέσω μη γραμμικής αλλαγής παραμέτρων στο χρόνο.
  • Το iOS CAMediaTimingFunction και το SwiftUI Animation.timingCurve υλοποιούν το easing μέσω κυβικής καμπύλης Bézier με δύο σημεία ελέγχου.
  • Το Android PathInterpolator και το Compose CubicBezierEasing — πλήρη ανάλογα iOS για προσαρμοσμένες καμπύλες εξομάλυνσης.
  • Οι καμπύλες easing μεταξύ πλατφορμών ορίζονται με πανομοιότυπα σημεία ελέγχου — η βάση ενοποίησης κινούμενων εικόνων.
  • Το Material Design 3 συνιστά fast-out-slow-in για εμφάνιση, linear-out-slow-in για εξαφάνιση.
  • Η κινούμενη εικόνα ελατηρίου στο SwiftUI (Animation.spring) και στο Compose (spring()) δημιουργεί φυσικό εφέ ελατηρίου με dampingFraction.
  • Το γραμμικό easing δεν συνιστάται για κινούμενες εικόνες διεπαφής — φαίνεται αφύσικο και μηχανικό.

Θα αναπτύξουμε μια εφαρμογή για κινητά έτοιμη για χρήση

Η IT Sectr δημιουργεί εφαρμογές iOS και Android για νεοφυείς επιχειρήσεις και επιχειρήσεις από το 2017. Θα σας συμβουλεύσουμε και θα προτείνουμε την καλύτερη λύση.

Συζήτηση έργου

Διαβάστε επίσης