Core Animation هو إطار الحركة منخفض المستوى من Apple يعمل على مستوى CALayer ويقوم بتجسيد المحتوى على وحدة معالجة الرسومات. 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) على وحدة معالجة الرسومات. كل UIView في iOS يحتوي على CALayer مدمج (view.layer) من خلاله يتم كل الرسم.
يعمل Core Animation على مبدأ الحركة الضمنية: بعض تغييرات خصائص CALayer تتحرك تلقائياً (CABasicAnimation لـ position، bounds، opacity، backgroundColor). تستخدم الحركات الضمنية CATransaction افتراضياً بمدة 0.25 ثانية ومنحنى easeInOut.
وفقاً لـ Apple WWDC 2024، يعالج Core Animation ما يصل إلى 120 إطاراً في الثانية على أجهزة ProMotion، باستخدام Metal لتجسيد GPU. حجم الطبقة النموذجية في الذاكرة هو 4 بايت لكل بكسل (RGBA) + ~100 بايت overhead لكل طبقة. يُوصى بعدم تجاوز 1000 طبقة على الشاشة لتحقيق 60 إطاراً في الثانية مستقرة.
CALayer هو أساس Core Animation. كل CALayer يحتوي على محتوى نقطي (أو مرجع نسيج GPU) ويحدد الهندسة (bounds، position، anchorPoint، transform، cornerRadius، borderWidth، shadow). لا تعالج الطبقات أحداث اللمس — UIView/UIScrollView هي المسؤولة عن ذلك. تشكل الطبقات تسلسلاً هرمياً (layer tree) يعكس التسلسل الهرمي للعرض.
يدعم Core Animation ثلاثة أشجار طبقات: model layer tree (الخصائص الفعلية)، presentation layer tree (العرض الحالي أثناء الحركة) و render tree (بيانات GPU). تُستخدم طبقة العرض لقراءة قيم الحركة الوسيطة في الوقت الفعلي.
لدى CALayer فئات فرعية متخصصة: CAShapeLayer (رسومات متجهة)، CAGradientLayer (تدرج)، CATextLayer (نص)، CATiledLayer (صور كبيرة مقسمة إلى بلاطات)، CAEAGLLayer/MetalLayer (OpenGL/Metal). CAShapeLayer هو الأكثر شيوعاً للحركة المخصصة بفضل دعم CGPath وحركة strokeStart/strokeEnd.
CABasicAnimation هي فئة فرعية من CAAnimation تحرك خاصية واحدة من CALayer من قيمة البداية (fromValue) إلى قيمة النهاية (toValue) أو بتغيير نسبي (byValue). تُضاف الحركة إلى الطبقة عبر layer.add(animation, forKey:) وتُنفذ في خادم التجسيد دون مشاركة التطبيق في كل إطار.
المفتاح (keyPath) هو سلسلة تحدد الخاصية: opacity، position، bounds، transform.rotation.z، cornerRadius، shadowOpacity، إلخ. يدعم Core Animation أكثر من 60 keyPath قابلة للحركة. للخصائص المخصصة، يُستخدم CATransaction وطبقة العرض.
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 في صفقة واحدة. تحدد CATransaction.begin() و CATransaction.commit() حدود الصفقة. داخل الصفقة يمكن تعيين معاملات مشتركة: duration، timingFunction، completionBlock، disableActions. CATransaction هي أساس الحركات الضمنية لـ CALayer.
تحدث الحركة الضمنية عندما تتغير خاصية CALayer خارج كتلة الحركة: layer.opacity = 0.5. ينشئ Core Animation تلقائياً CABasicAnimation بمدة من CATransaction الحالي (افتراضياً 0.25 ثانية). لتعطيل الحركة الضمنية، استخدم CATransaction.setDisableActions(true).
// CATransaction — التجميع والإكمال
func groupedAnimation() {
CATransaction.begin()
CATransaction.setAnimationDuration(1.5)
CATransaction.setAnimationTimingFunction(
CAMediaTimingFunction(name: .easeOut)
)
CATransaction.setCompletionBlock {
print("All animations completed")
}
// جميع التغييرات داخل الصفقة تتحرك بمدة 1.5
layer1.opacity = 0.3
layer2.position = CGPoint(x: 200, y: 300)
layer3.backgroundColor = UIColor.systemRed.cgColor
CATransaction.commit()
}
// تعطيل الحركة الضمنية
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 بمدة 0.6 و easeOut يجعل الحركة سلسة. layer.lineCap = .round يضيف نهايات مستديرة للخط لمظهر أنظف.
الأسئلة الشائعة
Core Animation يعمل على مستوى CALayer ويُتحكم به عبر CABasicAnimation و CATransaction. UIView.animate هو غلاف عالي المستوى حول Core Animation ينشئ تلقائياً CABasicAnimation لخصائص UIView. يوفر Core Animation تحكماً أكبر: keyPath، timingFunction، fillMode، التجميع عبر CATransaction.
الحركة الضمنية هي حركة تلقائية تحدث عند تغيير خاصية قابلة للحركة من CALayer خارج كتلة الحركة. على سبيل المثال، layer.opacity = 0.5 ينشئ CABasicAnimation بمدة 0.25 ثانية. تُدار الحركات الضمنية عبر CATransaction ويمكن تعطيلها باستخدام setDisableActions(true).
للخصائص المخصصة، قم بتنفيذ action(forKey:) في CALayer وأعد CAAnimation. بدلاً من ذلك، استخدم CALayer.display() للرسم اليدوي مع الحركة عبر CADisplayLink. للخصائص التي تدعم CABasicAnimation، يكفي تحديد keyPath كسلسلة نصية.
CALayer أخف من UIView: ليس لديه معالجات أحداث (touches، gestures)، لا يشارك في Auto Layout ولا يدعم إمكانية الوصول. CALayer نموذجي يشغل ~100 بايت مقابل ~300+ لـ UIView. يعالج Core Animation الطبقات في خادم التجسيد على GPU دون حظر الخيط الرئيسي.
الخلاصة
سنقوم بتطوير تطبيق جوال جاهز
تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.
اقرأ أيضًا