Spring Animation — ฟิสิกส์ของสปริงในแอนิเมชัน

ผู้แต่ง: IT Sectr เผยแพร่เมื่อ: 2026-03-01 เวลาอ่าน: 10 นาที

Spring Animation เป็นเทคนิคแอนิเมชันที่จำลองพฤติกรรมทางฟิสิกส์ของสปริง: มวล ความแข็ง (stiffness) การหน่วง (damping) และความเร็วเริ่มต้น แตกต่างจากการประมาณค่าเชิงเส้นและเส้นโค้งเบซิเอร์ แอนิเมชันสปริงสร้างการเคลื่อนไหวที่เป็นธรรมชาติด้วยเอฟเฟกต์การแกว่งแบบหน่วง ซึ่งดูเป็นธรรมชาติบนทุกอุปกรณ์ ตาม 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 จะคำนวณตำแหน่งของวัตถุในแต่ละช่วงเวลาตามพารามิเตอร์ทางฟิสิกส์: มวล ความแข็ง การหน่วง และความเร็วเริ่มต้น ผลลัพธ์คือการเคลื่อนไหวที่เป็นธรรมชาติและเป็นอินทรีย์ ซึ่งไม่ดู "เชิงกล"

แตกต่างจาก เส้นโค้ง Easing (easeIn, easeOut, cubic-bezier) ซึ่งมีระยะเวลาคงที่และวิถีถูกกำหนดไว้ล่วงหน้า Spring Animation ปรับตัวแบบไดนามิก: หากค่าเป้าหมายเปลี่ยนแปลงระหว่างแอนิเมชัน สปริงจะคำนวณวิถีใหม่จากตำแหน่งปัจจุบันอย่างราบรื่น สิ่งนี้สำคัญโดยเฉพาะสำหรับแอนิเมชันที่อาจถูกขัดจังหวะ — ลากเพื่อปิด ดึงเพื่อรีเฟรช การ์ดที่ปัดได้

ตามข้อมูลของ Apple WWDC 2025 การใช้แอนิเมชันสปริงแทนเส้นโค้งคงที่ช่วยลดความหน่วงที่รับรู้ได้ 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 = มาตรฐาน, 3.0 = องค์ประกอบหนัก
Initial Velocityใด ๆความเร็วเริ่มต้นในหน่วยพิกเซล/วินาทีความเร็วนิ้วเมื่อลากเพื่อปิด

การหน่วงวิกฤต (damping = 1.0) เป็นโหมดที่เหมาะสมที่สุดสำหรับแอนิเมชัน UI ส่วนใหญ่: วัตถุกลับสู่ตำแหน่งเป้าหมายเร็วที่สุดโดยไม่เกินเลย สำหรับเอฟเฟกต์การเด้ง (เช่น ดึงเพื่อรีเฟรช) ให้ใช้ damping = 0.3–0.5 สำหรับการปรากฏของหน้าต่างโมดัล — damping = 0.6–0.8 โดยมี stiffness = 300–500 มวลไม่ค่อยถูกเปลี่ยนแปลง — ค่ามาตรฐาน 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 ที่คำนวณระยะเวลาแอนิเมชันขั้นต่ำที่สปริงต้องใช้ในการเข้าสู่สมดุล ซึ่งหมายความว่าคุณไม่จำเป็นต้องเลือกระยะเวลาด้วยตนเอง — ระบบจะกำหนดเองว่าการหน่วงการแกว่งจะใช้เวลาเท่าใด สำหรับ 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 กับ Easing: เมื่อใดควรเลือกอะไร

Spring Animation และเส้นโค้ง Easing (easeInOut, FastOutSlowIn, decelerate) แก้ปัญหาที่แตกต่างกัน เส้นโค้ง Easing เป็นวิถีที่กำหนดทางคณิตศาสตร์ด้วยเวลาคงที่ Spring เป็นการจำลองทางฟิสิกส์ที่เวลาขึ้นอยู่กับพารามิเตอร์และเงื่อนไขเริ่มต้น สำหรับแอนิเมชันการปรากฏ/หายไปอย่างง่าย เส้นโค้ง Easing ก็เพียงพอ สำหรับแอนิเมชันที่เกี่ยวข้องกับการเคลื่อนไหวของผู้ใช้ (ลาก ปัด เลื่อน) Spring Animation ให้การตอบสนองที่เป็นธรรมชาติมากกว่า

สถานการณ์คำแนะนำพารามิเตอร์
การปรากฏขององค์ประกอบSpring (damping = 0.7, stiffness = 400)ปรากฏอย่างราบรื่นพร้อมการเกินเลยเล็กน้อย
ปัดเพื่อปิดSpring + ความเร็วเริ่มต้นsetStartVelocity(velocity), damping = 0.5
แอนิเมชันไอคอนSpring (damping = 0.3, stiffness = 600)การเด้งที่สังเกตได้สำหรับเอฟเฟกต์เน้น
ฟิสิกส์การเลื่อนSpring (ระบบ)ไม่ต้องปรับแต่ง — Android จัดการเอง
การเปลี่ยนขนาดEasing (FastOutSlowIn)Easing เชื่อถือได้มากกว่าสำหรับการเปลี่ยนแปลงเลย์เอาต์

รูปแบบที่ควรหลีกเลี่ยง: อย่าใช้ Spring Animation สำหรับการเคลื่อนไหวพารามิเตอร์เลย์เอาต์ (ความกว้าง/ความสูงของ 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 — นี่คือชุดเริ่มต้นสากลสำหรับ iOS และ Android สำหรับการปรากฏขององค์ประกอบ ให้เพิ่ม damping เป็น 0.7 สำหรับเอฟเฟกต์เน้น (ถูกใจ, เพิ่มในตะกร้า) ให้ลด 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() — เวอร์ชันพิเศษที่มีความเร็วเริ่มต้นจากท่าทางที่ปรับให้เหมาะกับแอนิเมชันการลาก

ทำไม 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 (นุ่ม), 600 (ปานกลาง), 1800 (สูง) บน 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

เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร

IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ

ปรึกษาโครงการ

อ่านเพิ่มเติม