UIView.animate เป็นวิธีการหลักในการเคลื่อนไหวคุณสมบัติของ UIView ใน iOS ซึ่ง implement ใน UIKit ผ่านบล็อกด้วย duration, delay และ options วิธีการนี้จะเคลื่อนไหว frame, alpha, transform, backgroundColor และคุณสมบัติอื่นที่สามารถเคลื่อนไหวได้ บทความนี้อธิบายไวยากรณ์ พารามิเตอร์ ตัวอย่างที่ใช้งานได้จริง และโครงสร้างภายในของการเคลื่อนไหว UIKit
ประเด็นสำคัญ
UIView.animate เป็นวิธีการแบบ static ของคลาส UIView ซึ่งเปิดตัวใน iOS 4 (2010) โดยมี API แบบประกาศสำหรับเคลื่อนไหวคุณสมบัติที่สามารถเคลื่อนไหวได้ของ UIView: frame, bounds, center, alpha, transform, backgroundColor วิธีการนี้รับบล็อก (การปิด) ที่มีการเปลี่ยนแปลงคุณสมบัติ — ระบบจะสร้าง CABasicAnimation โดยอัตโนมัติสำหรับแต่ละคุณสมบัติที่เปลี่ยนแปลง
ไวยากรณ์แบบบล็อกได้แทนที่ beginAnimations/commitAnimations แบบเก่า (iOS 2-3) และกลายเป็นมาตรฐานการเคลื่อนไหวใน UIKit การเคลื่อนไหว UIView.animate ทำงานบนเธรดหลักและไม่บล็อก UI โดยค่าเริ่มต้น ระยะเวลาการเคลื่อนไหวคือ 0.25 วินาทีพร้อมเส้นโค้ง easeInOut
ตามรายงานของ Apple WWDC 2023 วิธีการเคลื่อนไหวที่แนะนำในโปรเจกต์ใหม่คือ SwiftUI พร้อมตัวปรับแต่ง .animation() และ .transition() แต่ UIView.animate ยังคงเป็นเครื่องมือหลักสำหรับการรองรับ iOS 16 และต่ำกว่า รวมถึงการเปลี่ยนผ่านแบบกำหนดเองที่ซับซ้อน
UIView.animate ให้พารามิเตอร์หลักสามตัว: duration (ระยะเวลาเป็นวินาที), delay (ความล่าช้าก่อนเริ่ม) และ options (ชุดบิตมาสก์ UIView.AnimationOptions) Options ประกอบด้วย curve (easeInOut, easeIn, easeOut, linear), repeat, autoreverse, allowUserInteraction, beginFromCurrentState และ overrideInheritedDuration
| พารามิเตอร์ | ชนิด | คำอธิบาย |
|---|---|---|
| duration | TimeInterval | ระยะเวลาการเคลื่อนไหวเป็นวินาที (ชนิด Double) |
| delay | TimeInterval | ความล่าช้าก่อนเริ่มการเคลื่อนไหว |
| options | UIView.AnimationOptions | บิตมาสก์: curve, repeat, autoreverse, layoutSubviews |
| animations | () -> Void | บล็อกที่มีการเปลี่ยนแปลงคุณสมบัติที่เคลื่อนไหวได้ |
| completion | (Bool) -> Void | การปิดหลังจากการเคลื่อนไหวเสร็จสิ้น |
พารามิเตอร์ options รวมกันผ่านอาร์เรย์: [.curveEaseOut, .repeat, .autoreverse] การเคลื่อนไหวด้วย repeat และ autoreverse จะคืน View กลับสู่สถานะเริ่มต้นอย่างนุ่มนวลและทำซ้ำอย่างไม่จำกัด สำหรับจำนวนครั้งที่จำกัด ให้ใช้ animateKeyframes
การเคลื่อนไหวแบบ Spring เพิ่มเอฟเฟกต์สปริงทางฟิสิกส์: วัตถุไม่เพียงแค่เคลื่อนที่จากจุด A ไป B แต่เคลื่อนที่เลยเป้าหมายพร้อมการแกว่งแบบหน่วง พารามิเตอร์: usingSpringWithDamping (การหน่วง 0-1 โดยที่ 0 คือการแกว่งสูงสุด) และ initialSpringVelocity (ความเร็วสปริงเริ่มต้น)
Apple แนะนำ usingSpringWithDamping ในช่วง 0.4-0.8 สำหรับการเคลื่อนไหว UI ที่เป็นธรรมชาติ ค่า 0.5 สร้างการเด้งที่สังเกตเห็นได้โดยไม่รู้สึก "เหมือนยาง" initialSpringVelocity = 1.0 สอดคล้องกับความเร็ว 1 pt/วินาที ที่ 0 การเคลื่อนไหวเริ่มจากสถานะหยุดนิ่ง
// ตัวอย่างการเคลื่อนไหว spring และ keyframe
import UIKit
class AnimatedView: UIView {
func springBounce() {
// การเคลื่อนไหว spring พร้อมการหน่วง
UIView.animate(
withDuration: 0.8,
delay: 0,
usingSpringWithDamping: 0.5,
initialSpringVelocity: 1.0,
options: [.allowUserInteraction],
animations: {
self.transform = CGAffineTransform(scaleX: 1.2, y: 1.2)
self.alpha = 0.7
},
completion: { _ in
UIView.animate(withDuration: 0.3) {
self.transform = .identity
self.alpha = 1.0
}
}
)
}
func slideIn(from offset: CGFloat) {
self.transform = CGAffineTransform(translationX: offset, y: 0)
self.alpha = 0.0
UIView.animate(
withDuration: 0.6,
delay: 0.1,
options: [.curveEaseOut]
) {
self.transform = .identity
self.alpha = 1.0
}
}
}UIView.animateKeyframes ช่วยให้คุณแบ่งการเคลื่อนไหวออกเป็นหลายขั้นตอน (keyframe) โดยแต่ละขั้นมีเวลาและระยะเวลาสัมพัทธ์ของตัวเอง วิธีการ addKeyframe(withRelativeStartTime:relativeDuration:) รับค่าตั้งแต่ 0 ถึง 1 เทียบกับระยะเวลาการเคลื่อนไหวทั้งหมด
การเคลื่อนไหวแบบ keyframe มีประโยชน์สำหรับเอฟเฟกต์หลายขั้นตอน: การเต้นของปุ่ม (เพิ่มขึ้น → หยุดชั่วคราว → กลับมา), การปรากฏขององค์ประกอบตามลำดับ, การเปลี่ยนรูปที่ซับซ้อนพร้อมสถานะกลาง แต่ละ keyframe สามารถมีเส้นโค้งการเคลื่อนไหวของตัวเองผ่าน options
// การเคลื่อนไหว keyframe พร้อมลำดับที่ซับซ้อน
func complexPulse() {
UIView.animateKeyframes(withDuration: 2.0, delay: 0, options: [.repeat]) {
UIView.addKeyframe(withRelativeStartTime: 0.0, relativeDuration: 0.25) {
self.transform = CGAffineTransform(scaleX: 1.5, y: 1.5)
self.alpha = 0.5
}
UIView.addKeyframe(withRelativeStartTime: 0.25, relativeDuration: 0.25) {
self.transform = CGAffineTransform(scaleX: 0.8, y: 0.8)
self.alpha = 0.8
}
UIView.addKeyframe(withRelativeStartTime: 0.5, relativeDuration: 0.5) {
self.transform = .identity
self.alpha = 1.0
}
}
}
// การเคลื่อนไหวพร้อมการปิดแบบซ้อน
func animateCardTransition() {
UIView.animate(withDuration: 0.4, delay: 0, options: [.curveEaseOut]) {
self.transform = CGAffineTransform(scaleX: 0.95, y: 0.95)
} completion: { _ in
UIView.animate(withDuration: 0.3, delay: 0, options: [.curveEaseIn]) {
self.transform = .identity
}
}
}เบื้องหลัง UIView.animate มอบหมายการเคลื่อนไหวให้กับ CALayer ของแต่ละ UIView ผ่าน Core Animation (CAAnimation) เมื่อคุณเปลี่ยน frame ภายในบล็อกการเคลื่อนไหว ระบบจะสร้าง CABasicAnimation สำหรับคุณสมบัติ position และ bounds ของเลเยอร์ที่เกี่ยวข้อง หากเปลี่ยน alpha — CABasicAnimation สำหรับคุณสมบัติ opacity ของเลเยอร์
Core Animation ใช้กระบวนการ render server ที่แยกต่างหาก (backboardd บน iOS) ซึ่งประมวลผลการเคลื่อนไหวที่ 120 Hz (ProMotion) UIView.animate ไม่บล็อกเธรดหลัก — การเปลี่ยนแปลงคุณสมบัติจะถูกส่งไปยัง render server ซึ่งจะ interpolate เฟรมโดยไม่ต้องให้แอปพลิเคชันมีส่วนร่วม
ตามรายงานของ Apple การเคลื่อนไหวผ่าน UIView.animate มีค่าใช้จ่าย CPU ประมาณ 2-3% ต่อเลเยอร์ที่เปลี่ยนแปลงที่ 60 FPS สำหรับการเคลื่อนไหวจำนวนมาก (20+ วัตถุพร้อมกัน) แนะนำให้ใช้ CATransaction และการจัดการเลเยอร์ด้วยตนเอง
สำหรับการดีบักและแสดงภาพการเคลื่อนไหว UIKit ให้ใช้ Xcode Debug View Hierarchy — มันแสดง CAAnimations ที่ทำงานอยู่บนแต่ละเลเยอร์ ระยะเวลา เส้นโค้ง และสถานะปัจจุบัน การทำความเข้าใจโครงสร้างภายในของ Core Animation ช่วยหลีกเลี่ยงปัญหาประสิทธิภาพกับการเคลื่อนไหวที่ซับซ้อนและเลือกวิธีที่เหมาะสมที่สุดระหว่าง UIView.animate และการใช้ CABasicAnimation โดยตรง
สำหรับการดีบักและแสดงภาพการเคลื่อนไหว UIKit ให้ใช้ Xcode Debug View Hierarchy — มันแสดง CAAnimations ที่ทำงานอยู่บนแต่ละเลเยอร์ ระยะเวลา เส้นโค้ง และสถานะปัจจุบัน การทำความเข้าใจโครงสร้างภายในของ Core Animation ช่วยหลีกเลี่ยงปัญหาประสิทธิภาพกับการเคลื่อนไหวที่ซับซ้อนและเลือกวิธีที่เหมาะสมที่สุดระหว่าง UIView.animate และการใช้ CABasicAnimation โดยตรง
คำถามที่พบบ่อย
คุณสมบัติที่เคลื่อนไหวได้ ของ UIView: frame, bounds, center, alpha, transform (CGAffineTransform), backgroundColor การเปลี่ยนแปลง layoutIfNeeded() เมื่อแก้ไขข้อจำกัด Auto Layout ก็เคลื่อนไหวได้เช่นกัน คุณสมบัติอื่นไม่สามารถเคลื่อนไหวผ่าน UIView.animate — ให้ใช้ CALayer หรือ CADisplayLink สำหรับคุณสมบัติเหล่านั้น
UIView.animate ดำเนินการเคลื่อนไหวหนึ่งครั้งจากสถานะปัจจุบันไปยังสถานะเป้าหมาย UIView.animateKeyframes แบ่งระยะเวลาทั้งหมดออกเป็นหลายขั้นตอน (keyframe) โดยมีเวลาเริ่มต้นและระยะเวลาสัมพัทธ์แตกต่างกัน keyframe เหมาะสำหรับลำดับหลายขั้นตอน
การเคลื่อนไหว UIView.animate ถูกประมวลผลใน render server (backboardd) — กระบวนการ iOS ที่แยกต่างหาก เธรดหลักส่งเฉพาะค่าเริ่มต้นและค่าสุดท้ายของคุณสมบัติเท่านั้น การ interpolate เฟรมดำเนินการบน GPU ผ่าน Core Animation ด้วยความเร็วสูงถึง 120 FPS
เรียก layer.removeAllAnimations() บน UIView — ซึ่งจะลบ CAAnimations ทั้งหมดที่สร้างขึ้นเบื้องหลัง สำหรับการควบคุมที่แม่นยำยิ่งขึ้น ให้ใช้ CATransaction และตัวระบุการเคลื่อนไหวผ่าน CAAnimation.keyPath
สรุป
เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร
IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ