Spring Animation — ουσία, φυσική ελατηρίου σε κινήσεις

Συγγραφέας: IT Sectr Δημοσιεύτηκε: 2026-03-01 Χρόνος ανάγνωσης: 10 λεπ

Spring Animation — τεχνική κίνησης που μοντελοποιεί τη φυσική συμπεριφορά ενός ελατηρίου: μάζα, ακαμψία (stiffness), απόσβεση (damping) και αρχική ταχύτητα. Σε αντίθεση με τις γραμμικές παρεμβολές και τις καμπύλες Bézier, η κίνηση ελατηρίου δημιουργεί φυσική κίνηση με φαινόμενο αποσβενόμενων ταλαντώσεων που φαίνεται οργανική σε κάθε συσκευή. Σύμφωνα με το Material Design Guidelines (2026), το Spring Animation χρησιμοποιείται στο 73% των κινούμενων διεπαφών των κορυφαίων 100 εφαρμογών του App Store. Διαβάστε περισσότερα για άλλους τύπους κίνησης στον γενικό οδηγό κίνησης.

Βασικά σημεία

  • Spring Animation — κίνηση βασισμένη στο φυσικό μοντέλο ελατηρίου με μάζα και απόσβεση.
  • Damping — συντελεστής απόσβεσης ταλαντώσεων: 0 = άπειρες, 1 = χωρίς υπέρβαση.
  • Stiffness — ακαμψία ελατηρίου: όσο μεγαλύτερη, τόσο ταχύτερη επιστροφή σε ισορροπία.
  • CASpringAnimation — κλάση iOS για κίνηση ελατηρίου CALayer με υπολογισμό διάρκειας.
  • SpringAnimation — κλάση Android από τη βιβλιοθήκη AndroidX Dynamic Animation.

Τι είναι το Spring Animation;

Spring Animation — είναι μια κίνηση της οποίας η κίνηση περιγράφεται από την εξίσωση του αρμονικού ταλαντωτή με απόσβεση. Αντί να παρεμβάλλει την τιμή από 0 σε 1 σε σταθερό χρόνο, το Spring Animation υπολογίζει τη θέση του αντικειμένου σε κάθε στιγμή βάσει φυσικών παραμέτρων: μάζα (mass), ακαμψία (stiffness), απόσβεση (damping) και αρχική ταχύτητα (initialVelocity). Το αποτέλεσμα — φυσική, οργανική κίνηση που δεν μοιάζει «μηχανική».

Σε αντίθεση με τις καμπύλες Easing (easeIn, easeOut, cubic-bezier), όπου η διάρκεια είναι σταθερή και η τροχιά προκαθορισμένη, το Spring Animation προσαρμόζεται δυναμικά: αν αλλάξετε την τιμή-στόχο κατά τη διάρκεια της κίνησης, το ελατήριο υπολογίζει ξανά ομαλά την τροχιά από την τρέχουσα θέση. Αυτό είναι ιδιαίτερα σημαντικό για κινήσεις που μπορεί να διακοπούν — drag-to-dismiss, pull-to-refresh, σύρομενες κάρτες (swipeable cards).

Σύμφωνα με το Apple WWDC 2025, η χρήση κίνησης ελατηρίου αντί σταθερών καμπυλών μειώνει την αντιληπτή καθυστέρηση (perceived latency) κατά 30–50% χάρη στη φυσική επιτάχυνση στην αρχή και την ομαλή επιβράδυνση στο τέλος. Το Spring Animation συνιστάται για κάθε κίνηση που σχετίζεται με μετακίνηση: μετατόπιση, κλιμάκωση, εμφάνιση/εξαφάνιση.

Φυσικές παράμετροι ελατηρίου: damping και stiffness

Η συμπεριφορά του ελατηρίου καθορίζεται από τέσσερις παραμέτρους. Stiffness (ακαμψία) — δύναμη επιστροφής σε ισορροπία: τιμή 100–300 δίνει μαλακό ελατήριο για λίστες, 500–1000 — σκληρό για κουμπιά και διακόπτες. Damping (απόσβεση) — αντίσταση στην κίνηση: 0 — άπειρες ταλαντώσεις, 0.1–0.5 — αισθητές αποσβενόμενες ταλαντώσεις (φαινόμενο αναπήδησης), 1 — κρίσιμη απόσβεση (χωρίς ταλαντώσεις, ομαλή επιβράδυνση).

ΠαράμετροςΕύροςΕπίδρασηΠαράδειγμα χρήσης
Stiffness100–1000Ταχύτητα επιστροφής σε ισορροπία200 = λίστα, 600 = κουμπί
Damping0.0–1.0Απόσβεση ταλαντώσεων0.3 = αναπήδηση, 1.0 = χωρίς ταλαντώσεις
Mass0.1–10.0Αδράνεια αντικειμένου1.0 = standard, 3.0 = βαρύ στοιχείο
Initial VelocityΟποιαδήποτεΑρχική ταχύτητα σε pixels/sΤαχύτητα δαχτύλου σε drag-to-dismiss

Κρίσιμη απόσβεση (damping = 1.0) — βέλτιστη λειτουργία για τις περισσότερες κινήσεις UI: το αντικείμενο επιστρέφει στη θέση-στόχο όσο το δυνατόν γρηγορότερα χωρίς υπέρβαση. Για φαινόμενο αναπήδησης (π.χ. pull-to-refresh) χρησιμοποιήστε damping = 0.3–0.5. Για εμφάνιση modal παραθύρων — damping = 0.6–0.8 με stiffness = 300–500. Η μάζα σπάνια αλλάζει — η standard τιμή 1.0 είναι κατάλληλη για σχεδόν όλες τις περιπτώσεις.

Spring Animation σε iOS (Swift)

Στο iOS, το Spring Animation είναι διαθέσιμο μέσω UIView.animate(withDuration:delay:usingSpringWithDamping:initialSpringVelocity:) από το iOS 7 και CASpringAnimation (Core Animation) από το iOS 9. Η έκδοση UIView είναι απλούστερη και δημοφιλέστερη για κίνηση ιδιοτήτων View (transform, alpha, center). Η CASpringAnimation είναι ακριβέστερη και παρέχει πρόσβαση σε stiffness, damping και mass ως ξεχωριστές ιδιότητες.

swift
import UIKit

// UIView.animate με παραμέτρους ελατηρίου
let originalCenter = view.center

UIView.animate(
    withDuration: 0.8,
    delay: 0,
    usingSpringWithDamping: 0.5,
    initialSpringVelocity: 0.3,
    options: [.curveEaseInOut, .allowUserInteraction]
) {
    view.center = CGPoint(x: originalCenter.x + 100, y: originalCenter.y)
    view.transform = CGAffineTransform(scaleX: 1.2, y: 1.2)
} completion: { _ in
    UIView.animate(withDuration: 0.3) {
        view.transform = .identity
    }
}

// CASpringAnimation — ακριβής έλεγχος παραμέτρων
let spring = CASpringAnimation()
spring.keyPath = "transform.scale"
spring.fromValue = 1.0
spring.toValue = 1.5
spring.stiffness = 300
spring.damping = 10
spring.mass = 1.0
spring.initialVelocity = 5.0

"> CASpringAnimation.settlingDuration — υπολογισμένη διάρκεια
spring.duration = spring.settlingDuration
view.layer.add(spring, forKey: "scaleSpring")

CASpringAnimation.settlingDuration — μοναδική ιδιότητα του Core Animation που υπολογίζει την ελάχιστη διάρκεια κίνησης που χρειάζεται το ελατήριο για να φτάσει σε ισορροπία. Αυτό σημαίνει ότι δεν χρειάζεται να επιλέξετε μη αυτόματα το duration — το σύστημα καθορίζει μόνο του πόσο χρόνο θα διαρκέσει η απόσβεση των ταλαντώσεων. Για UIView.animate η διάρκεια ορίζεται ρητά και το damping 0.3–0.7 δίνει αισθητό φαινόμενο αναπήδησης. Για σύνδεση με UIPanGestureRecognizer, μεταβιβάστε το velocityRecognizer.velocity(in: view) ως initialSpringVelocity — έτσι η κίνηση συνεχίζει την κίνηση του δαχτύλου με την ίδια ταχύτητα.

Spring Animation σε Android (Kotlin)

Στο Android, το SpringAnimation είναι μέρος της βιβλιοθήκης AndroidX Dynamic Animation (androidx.dynamicanimation). Η κύρια κλάση — SpringAnimation, η οποία κινεί οποιαδήποτε float ιδιότητα ενός View ή προσαρμοσμένου αντικειμένου. Οι παράμετροι ορίζονται μέσω SpringForce — stiffness (προεπιλογή STIFFNESS_MEDIUM = 600) και dampingRatio (προεπιλογή DAMPING_RATIO_MEDIUM_BOUNCY = 0.5).

kotlin
// build.gradle.kts
implementation("androidx.dynamicanimation:dynamicanimation:1.1.0")

// Kotlin: SpringAnimation με προσαρμοσμένο SpringForce
import androidx.dynamicanimation.animation.SpringAnimation
import androidx.dynamicanimation.animation.SpringForce
import androidx.dynamicanimation.animation.FloatPropertyCompat

val springAnim = SpringAnimation(myView, SpringAnimation.TRANSLATION_X).apply {
    spring = SpringForce().apply {
        stiffness = SpringForce.STIFFNESS_LOW // 200.0f
        dampingRatio = SpringForce.DAMPING_RATIO_LOW_BOUNCY // 0.2f
        finalPosition = 300f
    }
    start()
}

// SpringAnimation με αρχική ταχύτητα από χειρονομία
myView.setOnTouchListener { _, event ->
    when (event.action) {
        MotionEvent.ACTION_DOWN -> {
            springAnim.cancel()
            false
        }
        MotionEvent.ACTION_UP -> {
            val velocity = velocityTracker?.getXVelocity() ?: 0f
            SpringAnimation(myView, SpringAnimation.TRANSLATION_X).apply {
                spring = SpringForce(0f) "> Επιστροφή στην αρχική θέση
                setStartVelocity(velocity)
                start()
            }
            true
        }
        else -> false
    }
}

"> SpringAnimation για προσαρμοσμένη ιδιότητα
val customAnim = SpringAnimation(
    myObject,
    object : FloatPropertyCompat<MyClass>("progress") {
        override fun getValue(obj: MyClass): Float = obj.progress
        override fun setValue(obj: MyClass, value: Float) { obj.progress = value }
    }
).apply { start() }

Σταθερές SpringForce: STIFFNESS_LOW (200), STIFFNESS_MEDIUM (600), STIFFNESS_HIGH (1800); DAMPING_RATIO_HIGH_BOUNCY (0.2), DAMPING_RATIO_MEDIUM_BOUNCY (0.5), DAMPING_RATIO_LOW_BOUNCY (0.75), DAMPING_RATIO_NO_BOUNCY (1.0). Για RecyclerView με κίνηση στοιχείων χρησιμοποιήστε SpringAnimation με DynamicAnimation.OnAnimationEndListener για απελευθέρωση πόρων. Για κίνηση πολλαπλών ιδιοτήτων χρησιμοποιήστε SpringAnimation.createFor(view, property).

Jetpack Compose: από το Compose 1.0, η κίνηση ελατηρίου είναι διαθέσιμη μέσω Animatable με spring() — animationSpec = spring(dampingRatio = 0.5f, stiffness = 300f). Αυτή είναι η προτιμώμενη μέθοδος για έργα Compose, καθώς το SpringAnimation από το DynamicAnimation είναι συμβατό μόνο με το σύστημα View. Η έκδοση Compose spring χρησιμοποιεί τον ίδιο φυσικό μηχανισμό, αλλά λειτουργεί στο πλαίσιο του Compose Animation System, σταματώντας αυτόματα κατά την αποκόλληση.

Spring Animation vs Easing: πότε να επιλέξουμε τι

Spring Animation και καμπύλες Easing (easeInOut, FastOutSlowIn, decelerate) λύνουν διαφορετικά προβλήματα. Οι καμπύλες Easing — μαθηματικά καθορισμένη τροχιά με σταθερό χρόνο. Το Spring — φυσική προσομοίωση, όπου ο χρόνος εξαρτάται από παραμέτρους και αρχικές συνθήκες. Για απλές κινήσεις εμφάνισης/εξαφάνισης, οι καμπύλες Easing είναι επαρκείς. Για κινήσεις που σχετίζονται με κίνηση χρήστη (drag, swipe, scroll), το Spring Animation δίνει πιο φυσική απόκριση.

ΣενάριοΣύστασηΠαράμετροι
Εμφάνιση στοιχείουSpring (damping = 0.7, stiffness = 400)Ομαλή εμφάνιση με ελαφριά υπέρβαση
Swipe-to-dismissSpring + αρχική ταχύτηταsetStartVelocity(velocity), damping = 0.5
Κίνηση εικονιδίουSpring (damping = 0.3, stiffness = 600)Αισθητή αναπήδηση για εφέ έμφασης
Φυσική κύλισηςSpring (συστημική)Μην προσαρμόζετε — το Android διαχειρίζεται μόνο του
Αλλαγή μεγέθουςEasing (FastOutSlowIn)Το Easing είναι πιο αξιόπιστο για αλλαγές layout

Anti-patterns: μην χρησιμοποιείτε Spring Animation για κίνηση παραμέτρων layout (πλάτος/ύψος View μέσω LayoutParams) — αυτό προκαλεί επαναϋπολογισμό της ιεραρχίας σε κάθε καρέ, οδηγώντας σε τράνταγμα και πτώση FPS. Για κίνηση χρώματος επίσης οι καμπύλες Easing είναι καλύτερες. Για κίνηση θέσης κύλισης χρησιμοποιήστε το συστημικό Scroller με fling — το Spring Animation δεν προσφέρει πλεονεκτήματα εδώ. Για μέγιστη απόδοση σε Android, περιορίστε τον αριθμό ταυτόχρονα ενεργών SpringAnimation σε 10–15.

Συχνές ερωτήσεις

Ποια είναι η διαφορά μεταξύ damping και stiffness;

Stiffness — ακαμψία ελατηρίου (δύναμη επιστροφής). Υψηλή τιμή (1000) — γρήγορη, απότομη κίνηση. Χαμηλή (100) — απαλή, αργή. Damping — απόσβεση (αντίσταση). Χαμηλή (0.2) — μακριές ταλαντώσεις με αναπήδηση. Υψηλή (1.0) — χωρίς ταλαντώσεις, ομαλή επιβράδυνση. Το Stiffness καθορίζει την ταχύτητα, το damping — την παρουσία και ένταση των ταλαντώσεων.

Πώς επιλέγουμε τις σωστές παραμέτρους Spring Animation;

Ξεκινήστε με damping = 0.5 και stiffness = 400 — αυτό είναι ένα universal σετ εκκίνησης για iOS και Android. Για εμφάνιση στοιχείων αυξήστε το damping σε 0.7. Για εφέ έμφασης (like, προσθήκη στο καλάθι) μειώστε το damping σε 0.3 με stiffness = 600. Για Material Motion χρησιμοποιήστε damping = 0.6 και stiffness = 300. Ελέγχετε την κίνηση σε πραγματική συσκευή, όχι σε προσομοιωτή.

Λειτουργεί το Spring Animation στο SwiftUI;

Ναι, στο SwiftUI η κίνηση ελατηρίου ορίζεται μέσω .animation(.spring(dampingFraction: 0.5, response: 0.5), value: state) ή .spring(blendDuration: 0.3) στο withAnimation. Τα response και dampingFraction αντιστοιχούν στα stiffness και damping από το UIKit. Για interactiveSpring() χρησιμοποιήστε .interactiveSpring() — ειδική έκδοση με αρχική ταχύτητα από τη χειρονομία, βελτιστοποιημένη για κινήσεις drag.

Γιατί το Spring Animation σε Android δεν σταματά;

Ελέγξτε το SpringForce.finalPosition — αν δεν έχει οριστεί ή είναι ίσο με την τρέχουσα τιμή, η κίνηση μπορεί να μην ξεκινήσει. Καλέστε springAnim.cancel() στο onPause() του Activity/Fragment. Για SpringAnimation σε RecyclerView χρησιμοποιήστε view.setOnDetachListener { animator.cancel() }. Για Jetpack Compose το SpringAnimation σταματά αυτόματα κατά τη σύνθεση.

Μπορεί το Spring Animation να διακοπεί ομαλά;

Ναι. Στο iOS καλέστε view.layer.removeAnimation(forKey:) — η κίνηση θα σταματήσει στο τρέχον καρέ. Στο Android καλέστε springAnim.cancel() — το αντικείμενο παραμένει στην τρέχουσα θέση. Για ομαλή μετάβαση σε νέα τιμή-στόχο ενημερώστε το finalPosition και μην καλέσετε cancel — το SpringAnimation θα υπολογίσει ξανά αυτόματα την τροχιά. Για SkipToEnd χρησιμοποιήστε springAnim.skipToEnd() σε Android.

Σύνοψη

  • Spring Animation — κίνηση βασισμένη στο φυσικό μοντέλο ελατηρίου με παραμέτρους stiffness και damping.
  • Damping — συντελεστής απόσβεσης (0 = άπειρες ταλαντώσεις, 1 = κρίσιμη απόσβεση).
  • Stiffness — ακαμψία ελατηρίου: 200 (soft), 600 (medium), 1800 (high) σε Android.
  • iOS: UIView.animate με usingSpringWithDamping (UIKit) ή CASpringAnimation (Core Animation).
  • Android: SpringAnimation + SpringForce από AndroidX Dynamic Animation.
  • Jetpack Compose: animationSpec = spring(dampingRatio, stiffness) μέσω Animatable.
  • Το Spring Animation είναι προτιμότερο από το Easing για κινήσεις με χειρονομίες (swipe, drag, pull-to-refresh).

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

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

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

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