CALayer เป็นคลาสพื้นฐานสำหรับเลเยอร์กราฟิกใน iOS ซึ่งเป็นส่วนหนึ่งของเฟรมเวิร์ก QuartzCore แต่ละ UIView ใน iOS มี CALayer ที่เกี่ยวข้องซึ่งจัดการการเรนเดอร์เนื้อหา แอนิเมชัน และการคอมโพสิตบน GPU ตาม Apple QuartzCore Documentation, 2025 CALayer รองรับคุณสมบัติที่สามารถทำแอนิเมชันได้มากกว่า 40 รายการและทำงานโดยตรงผ่าน Metal การทำความเข้าใจ CALayer เป็นสิ่งจำเป็นสำหรับการสร้างแอนิเมชันที่ราบรื่นและเพิ่มประสิทธิภาพของอินเทอร์เฟซ
ประเด็นสำคัญ
CALayer เป็นคลาสจากเฟรมเวิร์ก QuartzCore ที่จัดการภาพบิตแมปของพื้นที่สี่เหลี่ยมบนหน้าจอ มันเก็บคุณสมบัติทางภาพ: frame, backgroundColor, opacity, shadow, border, transform แตกต่างจาก UIView ตรงที่ CALayer ไม่จัดการเหตุการณ์สัมผัส ไม่มีส่วนร่วมใน Auto Layout และไม่มีวงจรชีวิตของ view controller
ในเชิงสถาปัตยกรรม CALayer ใช้รูปแบบ Model ในบริบทของ Core Animation เลเยอร์เก็บสถานะของคุณสมบัติทางภาพ ในขณะที่ Core Animation จัดการการประมาณค่าระหว่างสถานะระหว่างแอนิเมชัน การแยกนี้ช่วยให้สามารถทำแอนิเมชันคุณสมบัติใด ๆ ของเลเยอร์ได้โดยไม่ต้องวาดเนื้อหาใหม่ผ่าน drawRect
ตาม Apple WWDC 2024 CALayer ถูกเขียนใหม่เพื่อทำงานผ่าน Metal ท่อส่งการเรนเดอร์สมัยใหม่ประกอบด้วยสามขั้นตอน: Commit (อัปเดตคุณสมบัติบน CPU), Render (สร้างคำสั่ง GPU บน CPU) และ Composite (ดำเนินการคำสั่งบน GPU) CALayer มีส่วนร่วมในทั้งสามขั้นตอน โดยให้ข้อมูลสำหรับแต่ละขั้นตอน
แต่ละเลเยอร์สามารถมี sublayers — เลเยอร์ลูกที่เรนเดอร์เหนือเลเยอร์แม่ ลำดับชั้นเลเยอร์สะท้อนลำดับชั้น UIView แต่สามารถมีอยู่อย่างอิสระจากมัน นักพัฒนาสามารถสร้างเลเยอร์โดยอิสระจาก UIView ผ่าน CALayer() และเพิ่มลงในลำดับชั้นผ่าน addSublayer
UIView เป็นตัวห่อหุ้มรอบ CALayer ที่เพิ่ม: การจัดการสัมผัสผ่าน UIResponder, การมีส่วนร่วมใน Auto Layout, การแสดงใน storyboard และการรวมกับ UIViewController CALayer เป็นออบเจกต์น้ำหนักเบาที่สามารถใช้งานได้โดยไม่ต้องใช้ UIView สำหรับองค์ประกอบที่ใช้ภาพล้วน ๆ
ในทางปฏิบัติหมายความว่าหากองค์ประกอบไม่ต้องการการจัดการสัมผัสหรือเลย์เอาต์ ก็สามารถนำไปใช้เป็น CALayer ได้ ตัวอย่างเช่น แอนิเมชันพื้นหลัง ตัวบ่งชี้การโหลด องค์ประกอบตกแต่ง — ทั้งหมดนี้มีประสิทธิภาพมากกว่าเมื่อใช้งานผ่าน CALayer โดยหลีกเลี่ยงโอเวอร์เฮดของ UIView
คุณสมบัติพื้นฐาน ของ CALayer รวมถึงเฟรม การวางตำแหน่ง การแสดงผล และเอฟเฟกต์ภาพ frame กำหนดพื้นที่สี่เหลี่ยมของเลเยอร์ในพิกัดแม่ bounds กำหนดพิกัดภายใน และ position กำหนดศูนย์กลางของเลเยอร์ การเปลี่ยนแปลง position จะถูกทำแอนิเมชันโดยค่าเริ่มต้นผ่านแอนิเมชันโดยนัย
คุณสมบัติ contents อนุญาตให้ตั้งค่าเนื้อหาบิตแมปได้โดยตรง — ผ่าน CGImage หรือ CIImage นี่เป็นทางเลือกแทนการวาดผ่าน drawRect: หากภาพพร้อมแล้ว ก็สามารถส่งไปยัง contents และ Core Animation จะเรนเดอร์โดยไม่ต้องประมวลผลเพิ่มเติม
สำหรับแอนิเมชัน จะใช้ CABasicAnimation, CAKeyframeAnimation และ CATransition คลาสทั้งหมดนี้ทำงานผ่านคีย์พาธของคุณสมบัติ CALayer ซึ่งช่วยให้สามารถทำแอนิเมชันคุณลักษณะใด ๆ ก็ได้ ตั้งแต่ position ไปจนถึง transform.rotation.z
Apple มีคลาสย่อยเฉพาะทางหลายคลาสของ CALayer แต่ละคลาสแก้ไขงานเฉพาะ การเลือกคลาสย่อยที่เหมาะสมแทน CALayer พื้นฐานสามารถให้การปรับปรุงประสิทธิภาพอย่างมีนัยสำคัญผ่านการเร่งด้วยฮาร์ดแวร์
CAReplicatorLayer มีประโยชน์อย่างยิ่งสำหรับการสร้างรูปแบบที่ซ้ำกันโดยไม่ต้องทำโค้ดซ้ำ ตัวอย่างเช่น ตัวบ่งชี้การโหลดที่มี 10 จุด ใช้งานได้กับ CAReplicatorLayer หนึ่งตัวโดยใช้ instanceCount = 10 และออฟเซ็ตเวลาแอนิเมชัน instanceDelay
การเรนเดอร์ CALayer ดำเนินไปในสามเฟส Commit — เมื่อคุณสมบัติเลเยอร์เปลี่ยนแปลง ชุดการเปลี่ยนแปลงจะถูกสร้างบน CPU Render — Core Animation สร้างคำสั่ง Metal บน CPU ตามคุณสมบัติของเลเยอร์ Composite — GPU ดำเนินการคำสั่งและแสดงเฟรมบนหน้าจอ กระบวนการทั้งหมดซิงโครไนซ์กับอัตรารีเฟรชของจอแสดงผล
ในระหว่าง การคอมโพสิต ของหลายเลเยอร์ GPU จะรวมเข้าด้วยกันเป็นภาพสุดท้ายโดยคำนึงถึงความโปร่งใส มาสก์ และโหมดการเบลนด์ หากเลเยอร์มี opaque = true Core Animation จะปรับการคอมโพสิตให้เหมาะสม: แทนที่จะเป็นการเบลนด์อัลฟา จะทำการแทนที่พิกเซลอย่างง่าย ซึ่งเร็วกว่าอย่างมาก
ตาม Apple Performance Guidelines ปัจจัยหลักที่ทำให้การเรนเดอร์ CALayer ช้าลงคือ: ลำดับชั้น sublayer ที่ซับซ้อน (มากกว่า 30 เลเยอร์บนหน้าจอ) การใช้มาสก์ (คุณสมบัติ mask) การคำนวณเงาอัตโนมัติโดยไม่มี shadowPath และการใช้ shouldRasterize มากเกินไปสำหรับเลเยอร์ไดนามิก
Core Animation Instrument ใน XCode ช่วยให้ตรวจสอบเวลาเรนเดอร์ของแต่ละเลเยอร์ จำนวนบัฟเฟอร์นอกหน้าจอ และความถี่ในการเรียก drawRect เวลาเรนเดอร์ที่เหมาะสมที่สุดสำหรับ 60 FPS คือไม่เกิน 8 ms บน CPU และ 8 ms บน GPU
การเรนเดอร์นอกหน้าจอ — การเรนเดอร์เลเยอร์ลงในบัฟเฟอร์กลางก่อนแสดงบนหน้าจอ เกิดขึ้นเมื่อใช้ cornerRadius + masksToBounds กับเนื้อหา ความโปร่งใสกลุ่ม มาสก์ และ shouldRasterize แต่ละรอบนอกหน้าจอใช้เวลา 2–5 มิลลิวินาที ดังนั้นการเรนเดอร์นอกหน้าจอมากเกินไปจึงสำคัญต่อประสิทธิภาพ
เพื่อวินิจฉัยการเรนเดอร์นอกหน้าจอ ให้ใช้เครื่องมือ Color Offscreen-Rendered ใน Core Animation Instrument เลเยอร์สีเหลือง — นอกหน้าจอ สีน้ำเงิน — การเรนเดอร์โดยตรงบนหน้าจอ การลดรอบนอกหน้าจอให้เหลือน้อยที่สุดเป็นเทคนิคการเพิ่มประสิทธิภาพที่สำคัญใน iOS
ตัวอย่างแรกสาธิตการตั้งค่า CALayer พื้นฐานพร้อมการสร้างเงา การทำมุมโค้งมน และเส้นขอบ shadowPath ถูกระบุอย่างชัดเจนเพื่อเร่งการเรนเดอร์:
import UIKit
func configureLayer(_ view: UIView) {
let layer = view.layer
layer.cornerRadius = 16
layer.borderWidth = 2
layer.borderColor = UIColor.systemBlue.cgColor
layer.backgroundColor = UIColor.white.cgColor
layer.shadowColor = UIColor.black.cgColor
layer.shadowOpacity = 0.2
layer.shadowOffset = CGSize(width: 0, height: 4)
layer.shadowRadius = 8
layer.shadowPath = UIBezierPath(
roundedRect: view.bounds,
cornerRadius: layer.cornerRadius
).cgPath
}
ตัวอย่างที่สองแสดงแอนิเมชัน transform ผ่าน CABasicAnimation พร้อมการแปลง 3D แบบเปอร์สเปกทีฟ แอนิเมชันหมุนแกน Y สร้างเอฟเฟกต์พลิกการ์ด:
let flipAnimation = CABasicAnimation(keyPath: "transform")
var transform = CATransform3DIdentity
transform.m34 = -1.0 / 500.0
transform = CATransform3DRotate(transform, .pi, 0, 1, 0)
flipAnimation.toValue = NSValue(caTransform3D: transform)
flipAnimation.duration = 0.8
flipAnimation.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
cardLayer.add(flipAnimation, forKey: "flip")
ตัวอย่างที่สามสาธิตการใช้ CAGradientLayer เพื่อสร้างเกรเดียนต์พื้นหลัง เกรเดียนต์เรนเดอร์บน GPU และไม่ต้องการทรัพยากรเพิ่มเติมเมื่อปรับขนาด:
func addGradient(to view: UIView, colors: [UIColor]) {
let gradient = CAGradientLayer()
gradient.colors = colors.map { $0.cgColor }
gradient.locations = [0.0, 0.5, 1.0]
gradient.startPoint = CGPoint(x: 0.0, y: 0.0)
gradient.endPoint = CGPoint(x: 1.0, y: 1.0)
gradient.frame = view.bounds
view.layer.insertSublayer(gradient, at: 0)
}
คำถามที่พบบ่อย
UIView เป็นตัวห่อหุ้มรอบ CALayer ที่เพิ่มการจัดการสัมผัส Auto Layout และการรวมกับ UIViewController CALayer ทำงานเฉพาะกับการแสดงผลทางภาพและแอนิเมชัน ทำให้เบากว่าและมีประสิทธิภาพมากกว่าสำหรับงานกราฟิกล้วน ๆ
มากกว่า 40 คุณสมบัติ รวมถึง position, bounds, frame, opacity, backgroundColor, cornerRadius, transform, shadowOffset, shadowRadius, borderWidth และ borderColor แอนิเมชันเริ่มต้นโดยอัตโนมัติเมื่อเปลี่ยนคุณสมบัติภายในบล็อกแอนิเมชัน UIView.animate
ตั้งค่า shadowPath — เส้นขอบเงาที่ชัดเจนเป็น UIBezierPath หากไม่มี shadowPath Core Animation จะวิเคราะห์ช่องอัลฟาของเนื้อหาเพื่อคำนวณรูปร่างเงา ซึ่งต้องใช้รอบเพิ่มเติม ด้วย shadowPath เงาจะเรนเดอร์เป็นรูปทรงเรขาคณิตอย่างง่ายโดยไม่ต้องวิเคราะห์เนื้อหา
แอนิเมชันโดยนัย คือแอนิเมชันอัตโนมัติเมื่อเปลี่ยนคุณสมบัติที่ทำแอนิเมชันได้ของ CALayer นอกบล็อก UIView.animate ระยะเวลาเริ่มต้นคือ 0.25 วินาที สามารถปิดใช้งานได้ผ่าน CATransaction.setDisableActions(true) หรือตั้งค่าระยะเวลาแบบกำหนดเองผ่าน CATransaction.begin/commit
CAShapeLayer มีประสิทธิภาพมากกว่าเมื่อคุณต้องการแสดงรูปทรงเวกเตอร์ — เส้น วงกลม รูปหลายเหลี่ยม เส้นทางที่ซับซ้อน มันเรนเดอร์พาธบน GPU โดยไม่ต้องสร้างบัฟเฟอร์แรสเตอร์แยกต่างหาก CALayer พื้นฐานเหมาะสำหรับพื้นที่สี่เหลี่ยมที่มีพื้นหลัง เส้นขอบ และเงา
สรุป
เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร
IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ
อ่านเพิ่มเติม