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 เส้นโค้ง easing ที่เลือกอย่างถูกต้องจะลด เวลาการรับรู้ของแอนิเมชัน ลง 20–35% โดยไม่เปลี่ยนระยะเวลาจริง ที่ IT Sectr เราได้กำหนดมาตรฐานเส้นโค้ง ease-in-out (0.42, 0.0, 0.58, 1.0) เป็นมาตรฐานองค์กรสำหรับโปรเจกต์มือถือทั้งหมด

ประเด็นสำคัญ

  • Easing — ฟังก์ชันความเร็วแอนิเมชันที่เลียนแบบการเคลื่อนที่ทางกายภาพ: การเร่ง การชะลอ หรือการรวมกัน
  • CAMediaTimingFunction — คลาส iOS Core Animation พร้อมเส้นโค้งที่กำหนดไว้ล่วงหน้า 5 เส้นและ Bezier แบบลูกบาศก์ที่กำหนดเอง
  • SwiftUI Animation — ตัวปรับแต่ง .easeIn, .easeOut, .easeInOut, .spring และ .timingCurve สำหรับ easing แบบประกาศ
  • PathInterpolator — ค่าที่เทียบเท่า easing ใน Android ด้วยเส้นโค้ง Bezier แบบลูกบาศก์ผ่านจุดควบคุมสองจุด
  • Bezier แบบลูกบาศก์ — รูปแบบสากลสำหรับระบุเส้นโค้ง 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 อธิบายด้วยเส้นโค้ง Bezier แบบลูกบาศก์ โดยแกน 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 เส้นโค้ง easing ควรสอดคล้องกับบริบท: สำหรับการปรากฏ — ease-out (เริ่มต้นเร็ว) สำหรับการหายไป — ease-in (สิ้นสุดเร็ว)

Easing ใน iOS: CAMediaTimingFunction

ใน iOS การ easing ทำงานหลักผ่านคลาส CAMediaTimingFunction จาก Core Animation โดยรับเส้นโค้ง Bezier แบบลูกบาศก์เป็นจุดควบคุมสองจุด (c1x, c1y, c2x, c2y) และนำไปใช้กับ CAAnimation (CABasicAnimation, CAKeyframeAnimation) CAMediaTimingFunction รองรับ 5 ฟังก์ชันที่กำหนดไว้ล่วงหน้า: linear, easeIn, easeOut, easeInEaseOut และ default (เทียบเท่า easeInEaseOut)

CAMediaTimingFunction ทำงานที่ระดับ CALayer — แอนิเมชันทำงานในกระบวนการเซิร์ฟเวอร์เรนเดอร์แยกต่างหาก ซึ่งรับประกัน 60fps แม้กับการแปลงที่ซับซ้อน สำหรับแอนิเมชันคุณสมบัติ UIView (frame, alpha, transform) UIKit ใช้ UIView.animate พร้อมพารามิเตอร์ options: .curveEaseInOut ซึ่งภายในก็สร้าง CAMediaTimingFunction ด้วยเส้นโค้งที่เกี่ยวข้องเช่นกัน ใน iOS 17+ มีการเพิ่ม UIViewAnimationCurve.custom พร้อม BlockParameters สำหรับ Bezier ที่กำหนดเอง — ทำให้ไม่จำเป็นต้องเขียน 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) รับจุดควบคุม Bezier แบบลูกบาศก์โดยตรง — ซึ่งเป็นอะนาล็อกที่สมบูรณ์ของ 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 ด้วยเส้นโค้ง Bezier แบบลูกบาศก์ จุดควบคุมถูกระบุผ่าน 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 รับจุดควบคุม Bezier แบบลูกบาศก์ที่กำหนดจุดเริ่มต้นและสิ้นสุดที่ราบรื่นของการเคลื่อนที่

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 ดำเนินการแอนิเมชันในเซิร์ฟเวอร์เรนเดอร์ที่ 60/120 fps

SwiftUI: Easing ด้วย timingCurve

แอนิเมชันแบบประกาศใน SwiftUI ด้วยเส้นโค้งที่กำหนดเองและเอฟเฟกต์สปริง ตัวปรับแต่งแอนิเมชันผูกกับการเปลี่ยนแปลงของ 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) เว็บ (CSS ease-in-out) และการออกแบบ Interpolator คือการนำแนวคิดนี้ไปใช้ใน Android (TimeInterpolator) โดยพื้นฐานแล้วมันคือ สิ่งเดียวกัน — เส้นโค้งทางคณิตศาสตร์ของความเร็วแอนิเมชัน ความแตกต่างอยู่ที่ชื่อและ API ของแพลตฟอร์มเท่านั้น ในโปรเจกต์ข้ามแพลตฟอร์ม คำว่า easing ถูกใช้เป็นคำสากล

ฟังก์ชัน easing ใดบ้างที่พร้อมใช้งานใน iOS?

iOS มี CAMediaTimingFunction พร้อมฟังก์ชันที่กำหนดไว้ล่วงหน้า 5 ฟังก์ชัน: linear, easeIn, easeOut, easeInEaseOut และ custom (Bezier แบบลูกบาศก์) ใน SwiftUI มี Animation.easeIn, Animation.easeOut, Animation.easeInOut, Animation.spring และ Animation.interpolatingSpring สำหรับเส้นโค้งที่กำหนดเอง ให้ใช้ Animation.timingCurve(c0x, c0y, c1x, c1y, duration:)

สามารถใช้ฟังก์ชัน easing เดียวกันบน iOS และ Android ได้หรือไม่?

ได้ หากตั้งค่าเส้นโค้ง Bezier แบบลูกบาศก์เดียวกัน CAMediaTimingFunction ใน iOS และ PathInterpolator ใน Android รับจุดควบคุม Bezier แบบลูกบาศก์ (x1, y1, x2, y2) ตัวอย่างเช่น เส้นโค้ง ease-in-out (0.42, 0.0, 0.58, 1.0) จะให้พฤติกรรมเหมือนกันบนทั้งสองแพลตฟอร์ม Material Design ใช้แนวทางนี้สำหรับแอนิเมชันข้ามแพลตฟอร์ม

จะเลือกเส้นโค้ง easing ที่เหมาะสมสำหรับแอปพลิเคชันของฉันได้อย่างไร?

ใช้แนวทางการเคลื่อนที่ของ Material Design: สำหรับ การปรากฏขององค์ประกอบ — 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 ไปใช้ผ่านเส้นโค้ง Bezier แบบลูกบาศก์ที่มีจุดควบคุมสองจุด
  • 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 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ

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

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