Core Animation — กรอบงานอนิเมชันระดับต่ำของ Apple ที่ทำงานบนชั้น CALayer และให้การเรนเดอร์คอนเทนต์บน GPU Core Animation เป็นพื้นฐานของอนิเมชันทั้งหมดใน iOS และ macOS: UIKit, AppKit, SceneKit และ SpriteKit ถูกสร้างขึ้นบนกรอบงานนี้ บทความนี้อธิบายสถาปัตยกรรมของ CALayer, CABasicAnimation, CATransaction และเทคนิคเชิงปฏิบัติ
สิ่งสำคัญ
Core Animation — กรอบงานกราฟิกของ Apple ที่เปิดตัวใน Mac OS X 10.5 Leopard (2007) และถูกพอร์ตมายัง iOS ตั้งแต่ iPhone OS เวอร์ชันแรก (2007) Core Animation จัดการการคอมโพสิชัน อนิเมชัน และการเรนเดอร์เลเยอร์ (CALayer) บน GPU ทุก UIView ใน iOS มี CALayer ในตัว (view.layer) ที่ใช้สำหรับการวาดทั้งหมด
Core Animation ทำงานบนหลักการของ implicit animation: การเปลี่ยนแปลงบางอย่างของคุณสมบัติ CALayer จะถูกอนิเมชันโดยอัตโนมัติ Core Animation จะสร้าง CABasicAnimation สำหรับ position, bounds, opacity, backgroundColor โดย implict-อนิเมชันใช้ CATransaction เป็นค่าเริ่มต้นด้วย duration 0.25 วินาทีและเส้นโค้ง easeInOut
ตามข้อมูลของ Apple WWDC 2024, Core Animation สามารถประมวลผลได้ถึง 120 FPS บนอุปกรณ์ที่รองรับ ProMotion โดยใช้ Metal สำหรับการเรนเดอร์ผ่าน GPU ขนาดของเลเยอร์ทั่วไปในหน่วยความจำคือ 4 ไบต์ต่อพิกเซล (RGBA) + overhead ~100 ไบต์ต่อเลเยอร์ แนะนำให้ไม่เกิน 1,000 เลเยอร์ต่อหน้าจอเพื่อ 60 FPS ที่เสถียร
CALayer — พื้นฐานของ Core Animation แต่ละ CALayer ประกอบด้วยคอนเทนต์ bitmap (หรือลิงก์ไปยัง GPU texture) และกำหนดเรขาคณิต (bounds, position, anchorPoint, transform, cornerRadius, borderWidth, shadow) เลเยอร์ไม่จัดการเหตุการณ์การสัมผัส — UIView/UIScrollView รับผิดชอบส่วนนี้ เลเยอร์สร้างลำดับชั้น (layer tree) ที่สะท้อน view hierarchy
Core Animation รองรับสาม layer tree: model layer tree (คุณสมบัติปัจจุบัน), presentation layer tree (การแสดงผลปัจจุบันระหว่างอนิเมชัน) และ render tree (ข้อมูลสำหรับ GPU) Presentation layer ใช้สำหรับอ่านค่ากลางของอนิเมชันแบบเรียลไทม์
CALayer มีคลาสย่อยเฉพาะ: CAShapeLayer (กราฟิกเวกเตอร์), CAGradientLayer (เกรเดียนต์), CATextLayer (ข้อความ), CATiledLayer (ภาพขนาดใหญ่ที่แบ่งเป็นไทล์), CAEAGLLayer/MetalLayer (OpenGL/Metal) CAShapeLayer เป็นที่นิยมที่สุดสำหรับอนิเมชันแบบกำหนดเองเนื่องจากรองรับ CGPath และการอนิเมชัน strokeStart/strokeEnd
CABasicAnimation — คลาสย่อยของ CAAnimation ที่อนิเมชันหนึ่งคุณสมบัติของ CALayer จากค่าเริ่มต้น (fromValue) ไปยังค่าสุดท้าย (toValue) หรือการเปลี่ยนแปลงสัมพัทธ์ (byValue) อนิเมชันถูกเพิ่มไปยังเลเยอร์ผ่านเมธอด layer.add(animation, forKey:) และทำงานใน render server โดยไม่ต้องให้แอปพลิเคชันทำงานในทุกเฟรม
คีย์ (keyPath) — สตริงที่ระบุคุณสมบัติ: opacity, position, bounds, transform.rotation.z, cornerRadius, shadowOpacity ฯลฯ Core Animation รองรับ keyPath ที่อนิเมชันได้ 60+ รายการ สำหรับคุณสมบัติแบบกำหนดเอง ใช้ CATransaction และ presentation layer
import QuartzCore
// CABasicAnimation สำหรับ opacity และ cornerRadius
func animateLayer() {
let layer = CALayer()
layer.frame = CGRect(x: 50, y: 50, width: 100, height: 100)
layer.backgroundColor = UIColor.systemBlue.cgColor
view.layer.addSublayer(layer)
// 1. การอนิเมชันความโปร่งใส
let fadeAnim = CABasicAnimation(keyPath: "opacity")
fadeAnim.fromValue = 1.0
fadeAnim.toValue = 0.2
fadeAnim.duration = 2.0
fadeAnim.autoreverses = true
fadeAnim.repeatCount = .infinity
// 2. การอนิเมชันมุมโค้ง
let cornerAnim = CABasicAnimation(keyPath: "cornerRadius")
cornerAnim.fromValue = 0
cornerAnim.toValue = 50
cornerAnim.duration = 2.0
cornerAnim.autoreverses = true
cornerAnim.repeatCount = .infinity
layer.add(fadeAnim, forKey: "fade")
layer.add(cornerAnim, forKey: "corner")
}
// การอนิเมชัน position ด้วย ease-in-out
func moveLayer(_ layer: CALayer, to point: CGPoint) {
let anim = CABasicAnimation(keyPath: "position")
anim.fromValue = NSValue(cgPoint: layer.position)
anim.toValue = NSValue(cgPoint: point)
anim.duration = 0.6
anim.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
anim.isRemovedOnCompletion = false
anim.fillMode = .forwards
layer.add(anim, forKey: "move")
layer.position = point // อัปเดต model layer
}สำคัญ: CABasicAnimation เป็นการแสดงผลชั่วคราว (presentation layer) หลังจากอนิเมชันเสร็จสิ้น เลเยอร์จะกลับไปยังค่าเดิมของ model layer เพื่อบันทึกสถานะสุดท้าย ให้ตั้งค่า isRemovedOnCompletion = false, fillMode = .forwards และอัปเดต model layer ไปยังค่าสุดท้าย
CATransaction — กลไกการจัดกลุ่มอนิเมชัน Core Animation เป็น Transaction เดียวกัน CATransaction.begin() และ CATransaction.commit() กำหนดขอบเขตของ Transaction ภายใน Transaction สามารถกำหนดพารามิเตอร์ร่วม: duration, timingFunction, completionBlock, disableActions CATransaction เป็นพื้นฐานของ implicit-อนิเมชันของ CALayer
Implicit animation ทำงานเมื่อคุณสมบัติของ CALayer ถูกเปลี่ยนแปลงนอกบล็อกอนิเมชัน: layer.opacity = 0.5 Core Animation จะสร้าง CABasicAnimation โดยอัตโนมัติด้วย duration จาก CATransaction ปัจจุบัน (ค่าเริ่มต้น 0.25 วินาที) การปิด implicit-อนิเมชัน ใช้ CATransaction.setDisableActions(true)
// CATransaction — การจัดกลุ่มและ completion
func groupedAnimation() {
CATransaction.begin()
CATransaction.setAnimationDuration(1.5)
CATransaction.setAnimationTimingFunction(
CAMediaTimingFunction(name: .easeOut)
)
CATransaction.setCompletionBlock {
print("All animations completed")
}
// การเปลี่ยนแปลงทั้งหมดภายใน Transaction จะถูกอนิเมชันด้วย duration 1.5
layer1.opacity = 0.3
layer2.position = CGPoint(x: 200, y: 300)
layer3.backgroundColor = UIColor.systemRed.cgColor
CATransaction.commit()
}
// ปิดการใช้งาน implicit-อนิเมชัน
func updateWithoutAnimation() {
CATransaction.begin()
CATransaction.setDisableActions(true)
layer.frame = newFrame // ไม่มีการอนิเมชัน
CATransaction.commit()
}
// การอนิเมชันคุณสมบัติของ CAShapeLayer
func animateProgress(percentage: CGFloat) {
CATransaction.begin()
CATransaction.setAnimationDuration(0.8)
CATransaction.setCompletionBlock {
print("Progress updated to (percentage)%")
}
progressLayer.strokeEnd = percentage / 100.0
CATransaction.commit()
}Core Animation ผสานรวมกับ UIKit ผ่านเลเยอร์ของ UIView ตัวอย่างด้านล่างสาธิตการอนิเมชัน CAShapeLayer — วงกลมความคืบหน้าพร้อมอนิเมชันความยาวส่วนโค้งและการหมุนเลเยอร์ผ่าน CABasicAnimation
import UIKit
import QuartzCore
class CircularProgressView: UIView {
private let progressLayer = CAShapeLayer()
override func layoutSubviews() {
super.layoutSubviews()
let path = UIBezierPath(
arcCenter: CGPoint(x: bounds.midX, y: bounds.midY),
radius: bounds.width / 2 - 10,
startAngle: -.pi / 2,
endAngle: 3 * .pi / 2,
clockwise: true
)
progressLayer.path = path.cgPath
progressLayer.strokeColor = UIColor.systemBlue.cgColor
progressLayer.lineWidth = 8
progressLayer.fillColor = nil
progressLayer.strokeEnd = 0
progressLayer.lineCap = .round
layer.addSublayer(progressLayer)
}
func setProgress(_ value: CGFloat, animated: Bool = true) {
if animated {
CATransaction.begin()
CATransaction.setAnimationDuration(0.6)
CATransaction.setAnimationTimingFunction(
CAMediaTimingFunction(name: .easeOut)
)
progressLayer.strokeEnd = min(max(value, 0), 1)
CATransaction.commit()
} else {
progressLayer.strokeEnd = value
}
}
}CAShapeLayer อนิเมชันคุณสมบัติ strokeEnd จาก 0 ถึง 1 สร้างเอฟเฟกต์ "การเติมเต็ม" ของวงกลมความคืบหน้า CATransaction ด้วย duration 0.6 และ easeOut ทำให้อนิเมชันราบรื่น layer.lineCap = .round เพิ่มปลายเส้นที่โค้งมนเพื่อให้ดูสวยงามยิ่งขึ้น
คำถามที่พบบ่อย
Core Animation ทำงานบนระดับ CALayer และจัดการผ่าน CABasicAnimation, CATransaction UIView.animate — เป็น wrapper ระดับสูงเหนือ Core Animation ที่สร้าง CABasicAnimation ให้กับคุณสมบัติของ UIView โดยอัตโนมัติ Core Animation ให้การควบคุมมากกว่า: keyPath, timingFunction, fillMode, การจัดกลุ่มผ่าน CATransaction
Implicit animation — อนิเมชันอัตโนมัติเมื่อคุณสมบัติของ CALayer ที่อนิเมชันได้ถูกเปลี่ยนแปลงนอกบล็อกอนิเมชัน ตัวอย่างเช่น layer.opacity = 0.5 จะสร้าง CABasicAnimation ด้วย duration 0.25 วินาที Implicit-อนิเมชันถูกจัดการผ่าน CATransaction และปิดใช้งานได้ด้วย setDisableActions(true)
สำหรับคุณสมบัติแบบกำหนดเอง ให้สร้าง action(forKey:) ใน CALayer และคืนค่า CAAnimation หรือใช้ CALayer.display() สำหรับการวาดด้วยตนเองพร้อมอนิเมชันผ่าน CADisplayLink สำหรับคุณสมบัติที่รองรับ CABasicAnimation เพียงระบุ keyPath เป็นสตริง
CALayer เบากว่า UIView: ไม่มีตัวจัดการเหตุการณ์ (touches, gestures), ไม่เข้าร่วมใน Auto Layout และไม่รองรับ accessibility CALayer ทั่วไปใช้พื้นที่ ~100 ไบต์ เทียบกับ ~300+ ไบต์ของ UIView Core Animation ประมวลผลเลเยอร์ใน render server บน GPU โดยไม่บล็อก main thread
สรุป
เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร
IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ
อ่านเพิ่มเติม