Layer هو تجريد للمحتوى الرسومي يدير التمثيل المرئي لعناصر الواجهة في التطبيقات المحمولة. على عكس UIView، لا يعالج layer أحداث اللمس ولا يشارك في Auto Layout — مهمته الوحيدة هي العرض والرسوم المتحركة وتركيب البكسلات. وفقاً لـ Apple QuartzCore Documentation, 2025، كل UIView في iOS لديه CALayer مرتبط به يدير فعلياً الرسم والرسوم المتحركة. فهم بنية الطبقات يسمح للمطور بالتحكم في أداء العرض على مستوى البكسلات الفردية.
الخلاصة
Layer هو كائن منخفض المستوى في نظام الرسوميات يخزن صورة نقطية لجزء من الشاشة ويدير سماته المرئية: الموضع والحجم والتدوير والشفافية والظل واللون. في iOS، كل UIView لديه CALayer مدمج يمكن الوصول إليه عبر الخاصية layer. يمكن للمطور العمل مباشرة مع الطبقة، متجاوزاً UIView، للتحكم الدقيق في العرض.
تتبع بنية الطبقات نمط Model-View-Controller، حيث يعمل CALayer كنموذج — يخزن حالة الخصائص المرئية. Core Animation هي المتحكم الذي يدير انتقالات الرسوم المتحركة بين الحالات. View (UIView) هو غلاف اختياري يضيف معالجة اللمس والمشاركة في Auto Layout.
وفقاً لـ Apple WWDC 2024، يستخدم خط أنابيب العرض الحديث في iOS Metal لتركيب الطبقات. يتم عرض كل CALayer في مخزن مؤقت منفصل، ثم يقوم Core Animation بتركيب جميع المخازن في الصورة النهائية، مع مراعاة الشفافية وأوضاع المزج.
في Android، النظير للطبقات هو View وDrawable الخلفية، لكن العمل المباشر مع الطبقات الرسومية متاح عبر Canvas وRenderNode في Android 10+. فهم مفهوم الطبقة مهم لتحسين العرض على كلا المنصتين.
الفرق الرئيسي يكمن في مجال المسؤولية. View يتعامل مع إدخال المستخدم (اللمس والإيماءات) والتحديد (Auto Layout, frame) ودورة الحياة. Layer مسؤول حصراً عن العرض المرئي: عرض المحتوى ورسوم متحركة للخصائص والتركيب مع الطبقات الأخرى.
هذا الفصل يسمح بتخزين التمثيل النقطي للطبقة مؤقتاً بشكل مستقل عن View. إذا لم تتغير الطبقة، يستخدم Core Animation الإطار المخزن مؤقتاً دون استدعاء drawRect. للعناصر الثابتة، هذا يعطي زيادة كبيرة في الأداء دون تغيير الكود.
iOS يوفر تسلسلاً هرمياً غنياً للفئات الموروثة من CALayer. كل فئة فرعية محسنة لسيناريو محدد: عرض النص أو الرسوميات المتجهة أو التدرجات أو التحويلات ثلاثية الأبعاد. اختيار نوع الطبقة الصحيح يؤثر مباشرة على أداء العرض.
في Android، يتم تنفيذ مفهوم الطبقة عبر RenderNode وViewLayer وHardwareRenderer. بدءاً من Android 5.0 (API 21)، يتم عرض كل View في طبقة تسريع أجهزة خاصة بها، مما يسمح بالرسوم المتحركة دون استدعاء onDraw.
مرونة إضافية في iOS توفرها CAReplicatorLayer و CAEmitterLayer. الأول يستخدم لإنشاء أنماط متكررة، والثاني لأنظمة الجسيمات. كلاهما يعمل حصراً على GPU، مما يسمح بإنشاء تأثيرات بصرية معقدة دون فقدان الأداء.
تسلسل الطبقات في iOS يتبع بنية شجرية: كل CALayer يمكن أن يحتوي على طبقات فرعية متعددة. جميع التحويلات المطبقة على الطبقة الأم — القياس والتدوير والإزاحة — تُطبق تلقائياً على العناصر الفرعية. هذا يضمن الاتساق البصري أثناء الرسوم المتحركة.
تركيب المشهد يتم بواسطة Core Animation بالترتيب التالي: أولاً يتم عرض الخلفية، ثم كل طبقة فرعية بالترتيب من الأسفل إلى الأعلى. لكل طبقة، يتحقق Core Animation من خصائص الشفافية والأقنعة وأوضاع المزج، ثم يقوم بتركيبها في الإطار النهائي.
وفقاً لـ Apple Documentation، تركيب طبقة مع opaque = true وبدون قناة ألفا يتم بدون تمريرات إضافية — GPU ببساطة ينسخ البكسلات فوق الطبقة السابقة. إذا كانت الطبقة تحتوي على شفافية، يقوم GPU بإجراء مزج ألفا، مما يتطلب موارد حسابية إضافية.
في Android، يتم تركيب الطبقات عبر SurfaceFlinger — خدمة نظام تستقبل المخازن المؤقتة من كل تطبيق وتقوم بتركيبها حسب ترتيب z. كل Window في Android هو Surface منفصل يمكن أن يحتوي على طبقات رسومية متعددة.
CALayer.mask — خاصية تسمح بتطبيق قناع بشكل عشوائي على طبقة. يمكن أن يكون القناع أي CALayer آخر — على سبيل المثال، CAShapeLayer بمسار دائري أو CAGradientLayer لإنشاء انتقال سلس للشفافية. استخدام الأقنعة يزيد الحمل على GPU لأنه يتطلب تمرير عرض إضافي لحساب قيم ألفا لكل بكسل.
للقص المستطيلي البسيط، يوصى باستخدام cornerRadius و masksToBounds. على عكس الأقنعة عبر خاصية mask، يتم معالجة cornerRadius بواسطة الأجهزة في مرحلة التنقيط ولا يتطلب تمريراً إضافياً.
shouldRasterize هو خاصية رئيسية لـ CALayer لتحسين الأداء. عندما يتم ضبط shouldRasterize على true، يقوم Core Animation بعرض الطبقة وجميع طبقاتها الفرعية في مخزن مؤقت خارج الشاشة منفصل. في الإطارات اللاحقة، يتم استخدام الصورة النقطية المخزنة مؤقتاً بدلاً من إعادة العرض.
التخزين المؤقت فعال للطبقات الثابتة أو التي نادراً ما تتغير: الظلال والتدرجات والنص بزوايا دائرية. ومع ذلك، للطبقات التي يتم تحديثها بشكل متكرر (رسوم متحركة، فيديو، تمرير)، قد يؤدي التنقيط إلى تدهور الأداء لأن كل إطار يتطلب إعادة توليد ذاكرة التخزين المؤقت.
وفقاً لبحث Objc.io، الاستخدام الصحيح لـ shouldRasterize على iPad Pro يقلل وقت عرض شاشة معقدة من 25 مللي ثانية إلى 8 مللي ثانية — أكثر من ثلاثة أضعاف. الشرط الأساسي هو أن الطبقة يجب ألا تتغير أكثر من مرة كل 3–5 إطارات.
المثال الأول يوضح ضبط الخصائص المرئية الأساسية لـ CALayer في Swift — الزوايا الدائرية والظل والحدود:
import UIKit
class StyledView: UIView {
override func awakeFromNib() {
super.awakeFromNib()
layer.cornerRadius = 12
layer.masksToBounds = false
layer.shadowColor = UIColor.darkGray.cgColor
layer.shadowOpacity = 0.3
layer.shadowOffset = CGSize(width: 0, height: 4)
layer.shadowRadius = 8
}
}
المثال الثاني — إنشاء رسم متحرك لطبقة في Swift باستخدام CABasicAnimation. الخاصية position تتحرك دون تدخل UIView:
let animation = CABasicAnimation(keyPath: "position")
animation.fromValue = NSValue(cgPoint: CGPoint(x: 0, y: 0))
animation.toValue = NSValue(cgPoint: CGPoint(x: 150, y: 300))
animation.duration = 1.0
animation.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
targetLayer.add(animation, forKey: "moveAnimation")
المثال الثالث — العمل مع RenderNode في Kotlin على Android. RenderNode هو نظير مباشر لـ CALayer، يسمح بالتعامل مع الطبقات الرسومية على مستوى Canvas:
import android.graphics.renderer.RenderNode
fun createLayer(): RenderNode {
val node = RenderNode("customLayer")
node.setPosition(0, 0, 300, 200)
node.setScaleX(1.5f)
node.setScaleY(1.5f)
val canvas = node.beginRecording()
canvas.drawColor(android.graphics.Color.BLUE)
node.endRecording()
return node
}
الأسئلة الشائعة
UIView هو غلاف حول CALayer يضيف معالجة اللمس والمشاركة في Auto Layout. Layer يتعامل فقط مع العرض والرسوم المتحركة. يمكنك العمل مباشرة مع CALayer، لكن UIView ضروري لمعالجة أحداث الإدخال.
shouldRasterize يفعل التخزين المؤقت للطبقة في مخزن مؤقت خارج الشاشة منفصل. استخدمه للعناصر الثابتة أو التي نادراً ما تتغير مع ظلال أو تركيب معقد. لا تستخدمه للطبقات المتحركة بشكل متكرر — إعادة توليد ذاكرة التخزين المؤقت ستكون أكثر تكلفة من العرض المباشر.
اضبط الخاصية cornerRadius لتدوير الزوايا و masksToBounds = true لقص المحتوى حسب حدود الطبقة. للظلال، يجب أن يكون masksToBounds مساوياً لـ false، وإلا سيتم قص الظل — في هذه الحالة، استخدم طبقة منفصلة للظل.
نعم، RenderNode في Android 10+ يوفر وظائف مماثلة: إدارة الموضع والحجم والتدوير والشفافية على مستوى الطبقة الرسومية. Canvas وHardwareRenderer يوفران عرضاً قائماً على GPU. ومع ذلك، من الناحية المعمارية، لا يفصل Android بين View والطبقة بشكل صارم مثل iOS.
يتم حساب الظل في CALayer عبر shadowPath أو تلقائياً بناءً على قناة ألفا. الحساب التلقائي يتطلب اجتياز جميع بكسلات الطبقة، وهو مكلف. حدد shadowPath صريح — مستطيل أو UIBezierPath — هذا يسمح لـ GPU بحساب الظل دون اجتياز المحتوى.
الملخص
سنقوم بتطوير تطبيق جوال جاهز
تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.
اقرأ أيضًا