Auto Layout: ما هو التخطيط التكيفي لواجهات iOS

المؤلف: IT Sectr نُشر: 2026-02-21 وقت القراءة: 9 دق

Auto Layout هو نظام تحديد المواقع التكيفي لعناصر الواجهة من Apple، استناداً إلى القيود الرياضية (constraints). تم تطويره لنظام iOS 6 (2012)، ويسمح Auto Layout بإنشاء واجهات تعرض بشكل صحيح على جميع الأجهزة — من iPhone SE (4.7″) إلى iPad Pro (12.9″) و Dynamic Island. وفقاً لجلسة Apple WWDC Session 202 (2024)، أكثر من 90% من التطبيقات في App Store تستخدم Auto Layout أو بديله التصريحي — SwiftUI layout system. تصف Constraints العلاقات بين عناصر الواجهة من خلال معادلات خطية: view1.leading = view2.trailing + 8.

أهم النقاط

  • Auto Layout هو نظام التخطيط التكيفي من Apple باستخدام قيود رياضية (constraints) لجميع أحجام الشاشات.
  • Constraints هي معادلات خطية بالشكل view1.attribute = multiplier × view2.attribute + constant، يتم حلها بواسطة خوارزمية Cassowary.
  • UIStackView هو حاوية تدير تلقائياً constraints للعروض المتداخلة (أفقي/رأسي، محاذاة، توزيع).
  • NSLayoutConstraint هو API برمجي لإنشاء قيود في الكود مع التنشيط عبر isActive = true.
  • Safe Area و Layout Margins هو هوامش مدمجة في Auto Layout تمنع التداخل مع Dynamic Island و Notch و Home Indicator.

ما هو Auto Layout؟

Auto Layout هو نظام التخطيط التكيفي من Apple الذي يستخدم قيوداً رياضية (constraints) لتحديد مواضع عناصر الواجهة. على عكس التخطيط القائم على الإطارات (frame-based layout)، حيث يكون لكل عنصر إحداثيات ثابتة x, y, width, height، يصف Auto Layout العلاقات بين العناصر: «الزر يبعد 8pt عن الحافة اليمنى للأصل» أو «عرض حقل النص يساوي نصف عرض الشاشة». الآلية تستند إلى خوارزمية Cassowary، التي طورتها University of Washington (Greg J. Badros, 1999) ونفذتها Apple في iOS 6. يقوم Cassowary بحل نظام من المتباينات الخطية مع أولويات — Required (1000), Default High (750), Default Low (250) — مما يسمح بإدارة تعارضات القيود. يدعم Auto Layout ثلاثة أنواع من الأحجام: intrinsic (الحجم الطبيعي للعنصر المحدد بالمحتوى)، explicit (قيود محددة صراحة) و compressible/stretchable (وضع مرن عبر Content Hugging Priority و Compression Resistance Priority).

Intrinsic Content Size والأولويات

لكل عنصر واجهة في Auto Layout Intrinsic Content Size — حجم طبيعي يحدده محتواه. بالنسبة لـ UILabel يعتمد هذا على النص والخط، بالنسبة لـ UIImageView — على أبعاد الصورة. تتحكم Content Hugging Priority (مقاومة التمدد) و Compression Resistance Priority (مقاومة الضغط) في سلوك العنصر عندما تتغير المساحة المتاحة. القيم القياسية: 251 لـ hugging و 749 لـ compression resistance. إذا تنافس عنصران على المساحة، تحدد الأولوية أيهما يتمدد أولاً. فهم هذه الأولويات هو مفتاح حل Ambiguous Layout (التخطيط الغامض)، الذي يبرزه Xcode في المصحح.

تشريح الـ Constraint

يتم وصف الـ constraint بمعادلة: view1.attribute = multiplier × view2.attribute + constant. تشمل السمات leading, trailing, top, bottom, centerX, centerY, width, height, firstBaseline, lastBaseline. يستخدم multiplier للعلاقات النسبية (عرض view1 = 0.5 × عرض superview). يحدد constant إزاحة ثابتة (leading = superview.leading + 16). تتيح أدوات Interface Builder إنشاء constraints بصرياً عبر السحب بزر Ctrl، لكن التخطيطات المعقدة تتطلب إنشاءً برمجياً عبر NSLayoutConstraint أو VFL (Visual Format Language)، الذي توصي Apple باستبداله بـ NSLayoutConstraint منذ iOS 9.

كيف تعمل Constraints في iOS

يتم حل نظام الـ constraints كمسألة برمجة خطية: تجد خوارزمية Cassowary الترتيب الأمثل لجميع العناصر الذي يلبي جميع القيود مع مراعاة أولوياتها. إذا تناقضت الـ constraints مع بعضها، يحدث Unsatisfiable Layout — استثناء يسجله Xcode مع وصف تفصيلي للتعارض. إذا لم تكن هناك قيود كافية لتحديد موضع عنصر واحد على الأقل، يحدث Ambiguous Layout — تظهر العناصر في مواضع عشوائية. توصي Apple بمجموعة دنيا: لكل عنصر يجب تعيين position (x, y) و size (width, height) — صراحة أو عبر intrinsic content size. يمكن أن تكون الـ constraints من الدرجة الأولى: العنصر القائد (مثل superview) والتابع (العرض الفرعي) ينشئان تسلسلاً هرمياً.

خوارزمية Cassowary والأولويات

يستخدم Cassowary طريقة Sequential Quadratic Programming لحل أنظمة المتباينات الخطية. لكل constraint أولوية من 1 إلى 1000. Required (1000) هو قيد إلزامي؛ إذا تعذر تحقيقه، يتعطل التطبيق مع NSConstraintException. Default High (750) توصية؛ Default Low (250) الأقل أهمية. أثناء التعارض، يخفف Cassowary القيود ذات الأولوية الأقل. على سبيل المثال، إذا كان عنصران يتطلبان عرضاً ثابتاً لكن الشاشة ضيقة جداً، يتم تخفيف الـ constraint ذي الأولوية الأقل. في Xcode Debug View Hierarchy (أداة تصحيح متاحة منذ Xcode 6) يبرز فقط المشاكل مع Required constraints — الباقي يتم معالجته بدون خطأ.

UIStackView: الإدارة التلقائية للـ Constraints

UIStackView هو حاوية تم تقديمها في iOS 9 (2015) تقوم تلقائياً بإنشاء وإدارة constraints للعروض المتداخلة arrangedSubviews. يدعم UIStackView محورين: أفقي ورأسي. تحدد إعدادات distribution توزيع المساحة: fill (تعبئة نسبية حسب hugging priority), fillEqually (أحجام متساوية), fillProportionally (نسبي إلى intrinsic content size), equalSpacing (تباعد متساوٍ), equalCentering (مسافات متساوية بين المراكز). يحدد alignment المحاذاة العرضية: fill, leading, center, trailing (للأفقي) أو fill, top, center, bottom (للرأسي). يدير UIStackView تلقائياً التباعد ومحاذاة خط الأساس والتكيف مع Dynamic Type.

swift
import UIKit

class StackViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let stack = UIStackView()
        stack.axis = NSLayoutConstraint.Axis.vertical
        stack.distribution = .fillEqually
        stack.spacing = 8
        stack.translatesAutoresizingMaskIntoConstraints = false
        
        let label = UILabel()
        label.text = "Auto Layout Guide"
        label.font = UIFont.preferredFont(forTextStyle: .headline)
        
        let button = UIButton(type: .system)
        button.setTitle("Apply", for: .normal)
        
        stack.addArrangedSubview(label)
        stack.addArrangedSubview(button)
        view.addSubview(stack)
        
        NSLayoutConstraint.activate([
            stack.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            stack.centerYAnchor.constraint(equalTo: view.centerYAnchor),
            stack.leadingAnchor.constraint(greaterThanOrEqualTo: view.leadingAnchor, constant: 16),
            stack.trailingAnchor.constraint(lessThanOrEqualTo: view.trailingAnchor, constant: -16)
        ])
    }
}

ينشئ الكود UIStackView عمودياً بعنصرين (UILabel و UIButton)، موزعين بالتساوي (fillEqually) بتباعد 8pt. يتم توسيط الـ stack على الشاشة بهوامش لا تقل عن 16pt من الحواف. translatesAutoresizingMaskIntoConstraints = false إلزامي عند إنشاء constraints برمجياً — بدونه لا يعمل Auto Layout. في IT Sectr، يُستخدم UIStackView في 80% من شاشات مشاريع iOS لبناء نماذج تكيفية وقوائم إعدادات وبطاقات.

Stack Views المتداخلة

يمكن تداخل UIStackView: stack أفقي داخل stack رأسي هو نمط قياسي للتخطيطات المعقدة. يدير الـ stack الخارجي الصفوف، ويدير الداخلي الأعمدة داخل كل صف. يوفر الجمع بين axis و alignment و distribution في كل مستوى مرونة غير محدودة تقريباً دون أي constraint يدوي واحد. توصي Apple باستخدام UIStackView كأداة التخطيط الرئيسية في UIKit، مع اللجوء إلى NSLayoutConstraint اليدوي فقط للحالات التي لا تغطيها الـ stacks: العروض المتداخلة، تحديد المواقع بدقة البكسل، الرسوم المتحركة المخصصة للـ bounds.

NSLayoutConstraint: إنشاء القيود برمجياً

NSLayoutConstraint هو API برمجي لإنشاء قيود فردية في الكود. يتم إنشاء كل constraint عبر مُهيئ مع معاملات: item, attribute, relatedBy, toItem, attribute, multiplier, constant. منذ iOS 9، قدمت Apple Anchor API — بناء جملة أكثر قابلية للقراءة عبر خصائص view.leadingAnchor, view.trailingAnchor, view.topAnchor, view.bottomAnchor, view.centerXAnchor, view.centerYAnchor, view.widthAnchor, view.heightAnchor. يقوم Anchor API تلقائياً بتعيين relatedBy = .equal ويستخدم First Item/Second Item من Anchors، مما يقلل الكود بنسبة 40% مقارنة بـ NSLayoutConstraint الكلاسيكي.

swift
import UIKit

class ConstraintViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let childView = UIView()
        childView.backgroundColor = .systemBlue
        childView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(childView)
        
        NSLayoutConstraint.activate([
            childView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 24),
            childView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 16),
            childView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -16),
            childView.heightAnchor.constraint(equalToConstant: 120),
            childView.bottomAnchor.constraint(lessThanOrEqualTo: view.bottomAnchor, constant: -24)
        ])
    }
}

يقوم الكود بتحديد موضع childView بهوامش من safeAreaLayoutGuide (top) وحواف الشاشة (leading/trailing). يضمن lessThanOrEqualTo للـ bottom عدم تجاوز العرض للحد السفلي. يلقي Anchor API استثناء في وقت الترجمة إذا كانت الـ anchors غير متوافقة (مثلاً، خلط leadingAnchor مع rightAnchor)، مما يمنع أخطاء وقت التشغيل. توصي Apple بـ Anchor API كمعيار لـ Auto Layout البرمجي منذ iOS 9.

Safe Area و Layout Margins في Auto Layout

Safe Area هي منطقة الشاشة التي لا تغطيها عناصر النظام: Dynamic Island و Notch و Status Bar و Home Indicator والزوايا الدائرية. في iOS 11، استبدلت Apple topLayoutGuide/bottomLayoutGuide بـ safeAreaLayoutGuide، الذي يتكيف تلقائياً مع اتجاه الجهاز ووجود قطع الشاشة. Layout Margins هي هوامش داخلية افتراضية للعرض (16pt في iOS، 20pt في iPadOS). بالنسبة لـ UILayoutGuide يمكن تعيين directionalLayoutMargins مخصصة مع مراعاة التوطين RIGHT-TO-LEFT. يحترم Auto Layout تلقائياً safe area عند استخدام safeAreaLayoutGuide في الـ anchors.

التكيف مع Dynamic Island و Notch

على الأجهزة ذات Dynamic Island (iPhone 14 Pro والإصدارات الأحدث) و Notch (iPhone X–13)، تستثني Safe Area 44pt من الأعلى في الوضع العمودي (59pt مع Dynamic Island في الحالة النشطة). يضيف Home Indicator 34pt من الأسفل. للتكيف الصحيح، يجب ربط جميع constraints العلوية بـ safeAreaLayoutGuide.topAnchor، وليس view.topAnchor. يجب ربط constraints السفلية بـ safeAreaLayoutGuide.bottomAnchor أو view.bottomAnchor مع هامش لـ Home Indicator. في IT Sectr، نختبر جميع الشاشات على محاكيات iPhone SE (2022) و iPhone 14 Pro Max و iPad Pro 12.9″ — ثلاثة أجهزة تغطي جميع متغيرات safe area.

أخطاء Auto Layout الشائعة

الأخطاء الأكثر شيوعاً عند العمل مع Auto Layout: نسيان translatesAutoresizingMaskIntoConstraints = false، تعارض Required constraints (الأولوية 1000)، Ambiguous Layout (قيود غير كافية لتحديد الموضع)، Content Hugging Priority غير صحيح لـ UILabel متعدد الأسطر وخلط anchors leading/trailing مع left/right. يعرض Xcode 15+ مشكلات التخطيط في Runtime Issue Navigator ويقدم تصحيحات تلقائية. للتخطيطات المعقدة، استخدم Debug View Hierarchy: العلامات الصفراء تشير إلى ambiguous layout، الحمراء تشير إلى unsatisfiable.

الخطأالسببالحل
translatesAutoresizingMaskIntoConstraints = trueAuto Layout غير مفعل للعرضتعيين false لجميع العروض البرمجية
Unsatisfiable Layoutتعارض Required (1000) constraintsخفض أولوية أحدها إلى Default High (750)
Ambiguous Layoutقيود غير كافية لـ x/y/w/hإضافة constraint مفقود أو التحقق من intrinsic size
اقتطاع النص في UILabelContent Hugging Priority أقل من المنافسرفع hugging priority إلى 252+
خلط anchors LTR/RTLleadingAnchor مع rightAnchorاستخدام leading/trailing فقط لدعم RTL

الأسئلة المتكررة

كيف يختلف Auto Layout عن التخطيط القائم على الإطارات؟

التخطيط القائم على الإطارات يحدد إحداثيات ثابتة x, y, width, height لكل عنصر. يستخدم Auto Layout قيوداً رياضية (constraints) — علاقات بين العناصر: «label.leading = button.trailing + 8». التخطيط القائم على الإطارات لا يتكيف مع حجم الشاشة؛ يعيد Auto Layout حساب المواضع تلقائياً عند التدوير أو Split View أو تغيير Dynamic Type.

متى يجب استخدام UIStackView بدلاً من NSLayoutConstraint؟

UIStackView مثالي للتخطيطات الخطية: الصفوف والأعمدة والنماذج وقوائم المعلمات. NSLayoutConstraint ضروري للعروض المتداخلة وتحديد المواقع بدقة البكسل والرسوم المتحركة المخصصة للـ bounds والحالات التي يكون فيها توزيع المساحة غير متساوٍ ولا يغطيه distribution في UIStackView. عملياً، 80% من التخطيطات تُحل بـ UIStackView و 20% بـ constraints يدوية.

ما هو Content Hugging Priority في Auto Layout؟

Content Hugging Priority (مقاومة التمدد) هي أولوية تحدد مدى مقاومة العنصر لزيادة حجمه فوق Intrinsic Content Size. القيمة الافتراضية هي 251. إذا تنافس عنصران على مساحة حرة، يبقى العنصر ذو hugging priority الأعلى بحجمه بينما يتمدد الثاني. Compression Resistance Priority (749 افتراضياً) تعمل بالمثل للضغط.

كيف يعمل Auto Layout مع Dynamic Type؟

يتكيف Auto Layout تلقائياً مع Dynamic Type إذا كانت الـ constraints تستخدم intrinsic content size للتسميات. عند زيادة حجم الخط، يتمدد UILabel مزاحاً العناصر المجاورة عبر الـ constraints. يعيد UIStackView مع distribution = fillProportionally توزيع المساحة نسبياً مع الأحجام الجديدة. Safe Area و Layout Margins تراعي أيضاً إعدادات إمكانية الوصول.

لماذا يحدث Unsatisfiable Layout؟

Unsatisfiable Layout يحدث عندما يتعارض اثنان من Required (priority = 1000) constraints مع بعضهما: مثلاً، view.leading = superview.leading + 16 و view.trailing = superview.leading + 200 مع superview عرضه 100pt. لا تستطيع خوارزمية Cassowary إيجاد حل ويتعطل التطبيق مع NSConstraintException. الحل هو خفض أولوية أحد الـ constraints المتعارضة إلى Default High (750).

الخلاصة

  • Auto Layout هو نظام التخطيط التكيفي من Apple القائم على خوارزمية Cassowary، التي تحل نظام قيود خطية بأولويات.
  • Constraints هي معادلات بالشكل view1.attribute = multiplier × view2.attribute + constant بأولويات من 1 إلى 1000 (Required).
  • UIStackView هو حاوية تدير تلقائياً constraints للـ arrangedSubviews مع دعم المحاور و distribution و alignment.
  • NSLayoutConstraint مع Anchor API هو المعيار البرمجي منذ iOS 9، مما يقلل الكود بنسبة 40% مقارنة بـ API الكلاسيكي.
  • Safe Area هي المنطقة الخالية من Dynamic Island و Notch و Home Indicator؛ إلزامية لربط constraints العلوية والسفلية.
  • الأخطاء الشائعة — نسيان translatesAutoresizingMaskIntoConstraints وتعارض Required و Ambiguous Layout وخلط anchors LTR/RTL.
  • Intrinsic Content Size والأولويات (hugging 251, compression 749) تتحكم في سلوك العناصر عند تغير المساحة المتاحة.

سنقوم بتطوير تطبيق جوال جاهز

تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.

مناقشة المشروع

اقرأ أيضًا