Auto Layout — سیستم موقعیتیابی تطبیقی عناصر رابط کاربری از اپل، مبتنی بر محدودیتهای ریاضی (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 وابستگیهای بین عناصر UI را از طریق معادلات خطی توصیف میکنند: view1.leading = view2.trailing + 8.
مهم
Auto Layout — سیستم طراحی تطبیقی اپل است که از محدودیتهای ریاضی (constraints) برای موقعیتیابی عناصر UI استفاده میکند. بر خلاف طراحی قابمحور (frame-based layout) که در آن هر عنصر مختصات ثابت x، y، width، height دارد، Auto Layout روابط بین عناصر را توصیف میکند: «دکمه در 8pt از لبه راست والد قرار دارد» یا «عرض فیلد متنی برابر با نصف عرض صفحه است». این مکانیزم بر اساس الگوریتم Cassowary است که در University of Washington (Greg J. Badros، 1999) توسعه یافته و توسط اپل در iOS 6 پیادهسازی شده است. Cassowary سیستم نابرابریهای خطی با اولویتها را حل میکند — Required (1000)، Default High (750)، Default Low (250) — که امکان مدیریت تضادهای محدودیتها را فراهم میکند. Auto Layout از سه نوع اندازه پشتیبانی میکند: intrinsic (اندازه طبیعی عنصر که توسط محتوا تعیین میشود)، explicit (constraint صریحاً تعیین شده) و compressible/stretchable (حالت الاستیک از طریق Content Hugging Priority و Compression Resistance Priority).
هر عنصر UI در Auto Layout دارای Intrinsic Content Size — اندازه طبیعی تعیین شده توسط محتوای خود است. برای UILabel این به متن و فونت بستگی دارد، برای UIImageView — به ابعاد تصویر. Content Hugging Priority (مقاومت در برابر کشیده شدن) و Compression Resistance Priority (مقاومت در برابر فشرده شدن) رفتار عنصر را هنگام تغییر فضای موجود مدیریت میکنند. مقادیر استاندارد: 251 برای hugging و 749 برای compression resistance. اگر دو عنصر برای فضا رقابت کنند، اولویت تعیین میکند کدام یک ابتدا کشیده میشود. درک این اولویتها کلید رفع Ambiguous Layout (طرحبندی مبهم) است که Xcode در دیباگر برجسته میکند.
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) دارند که اپل توصیه میکند از iOS 9 با NSLayoutConstraint جایگزین شود.
سیستم constraints به عنوان یک مسئله برنامهریزی خطی حل میشود: الگوریتم Cassowary مکان بهینه همه عناصر را پیدا میکند و تمام محدودیتها را با در نظر گرفتن اولویتهایشان برآورده میکند. اگر constraints با یکدیگر تضاد داشته باشند، Unsatisfiable Layout رخ میدهد — استثنایی که Xcode با شرح دقیق تضاد ثبت میکند. اگر constraints برای تعیین موقعیت حداقل یک عنصر کافی نباشند، Ambiguous Layout رخ میدهد — عناصر در موقعیت دلخواه نمایش داده میشوند. اپل حداقل مجموعه را توصیه میکند: برای هر عنصر باید position (x، y) و size (width، height) — به صورت صریح یا از طریق intrinsic content size تعیین شود. Constraints میتوانند first-class باشند: عنصر اصلی (مثلاً superview) و عنصر وابسته (view فرزند) سلسلهمراتب ایجاد میکنند.
Cassowary از روش Sequential Quadratic Programming برای حل سیستمهای نابرابریهای خطی استفاده میکند. هر constraint دارای اولویت از 1 تا 1000 است. Required (1000) — محدودیت اجباری؛ اگر قابل اجرا نباشد، برنامه با NSConstraintException crash میکند. Default High (750) — توصیهای؛ Default Low (250) — کم اهمیتترین. در صورت تضاد، Cassowary محدودیتهای با اولویت پایینتر را تضعیف میکند. به عنوان مثال، اگر دو عنصر عرض ثابت نیاز داشته باشند و صفحه خیلی باریک باشد، constraint با اولویت پایینتر تضعیف میشود. در Xcode Debug View Hierarchy (ابزار دیباگ موجود از Xcode 6) فقط مشکلات مربوط به Required constraints را برجسته میکند — بقیه بدون خطا پردازش میشوند.
UIStackView — کانتینری که در iOS 9 (2015) معرفی شد و به طور خودکار constraints را برای arrangedSubviews تو در تو ایجاد و مدیریت میکند. UIStackView از دو محور پشتیبانی میکند: horizontal (چیدمان افقی) و vertical (عمودی). تنظیمات distribution نحوه توزیع فضا را تعیین میکند: fill (پر کردن متناسب با hugging priority)، fillEqually (اندازههای مساوی)، fillProportionally (متناسب با intrinsic content size)، equalSpacing (فاصلههای مساوی)، equalCentering (فاصله مساوی بین مراکز). Alignment تراز کردن را در عرض محور تعیین میکند: fill، leading، center، trailing (برای horizontal) یا fill، top، center، bottom (برای vertical). UIStackView به طور خودکار spacing، baseline alignment و سازگاری با Dynamic Type را مدیریت میکند.
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"
label.font = UIFont.preferredFont(forTextStyle: .headline)
let button = UIButton(type: .system)
button.setTitle("اعمال", 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 برای ساخت فرمهای تطبیقی، لیست تنظیمات و کارتها استفاده میشود.
UIStackViewها میتوانند تو در تو باشند: stack افقی داخل vertical — الگوی استاندارد برای طرحبندیهای پیچیده. stack بیرونی ردیفها را مدیریت میکند، stack داخلی — ستونهای داخل ردیف. ترکیب axis، alignment و distribution در هر سطح عملاً انعطافپذیری نامحدودی را بدون حتی یک constraint دستی فراهم میکند. اپل استفاده از UIStackView را به عنوان ابزار اصلی layout در UIKit توصیه میکند و تنها در مواردی که stack پوشش نمیدهد به NSLayoutConstraint دستی مراجعه میکند: viewهای همپوشان، موقعیتیابی دقیق پیکسلی، انیمیشن سفارشی bounds.
NSLayoutConstraint — API برنامهنویسی برای ایجاد محدودیتهای فردی در کد. هر constraint از طریق مقداردهنده با پارامترها ایجاد میشود: item، attribute، relatedBy، toItem، attribute، multiplier، constant. از iOS 9 اپل 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 از Anchor استفاده میکند و کد را 40٪ در مقایسه با NSLayoutConstraint کلاسیک کاهش میدهد.
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 تضمین میکند که view از مرز پایینی خارج نشود. Anchor API در مرحله کامپایل استثنا پرتاب میکند اگر anchorها ناسازگار باشند (مثلاً leadingAnchor با rightAnchor مخلوط شود)، که از خطاهای runtime جلوگیری میکند. اپل Anchor API را به عنوان استاندارد برای Auto Layout برنامهنویسی از iOS 9 توصیه میکند.
Safe Area — ناحیهای از صفحه که توسط عناصر سیستمی پوشانده نشده است: Dynamic Island، Notch، Status Bar، Home Indicator، گوشههای گرد. در iOS 11 اپل topLayoutGuide/bottomLayoutGuide را با safeAreaLayoutGuide جایگزین کرد که به طور خودکار با جهت دستگاه و وجود بریدگی صفحه سازگار میشود. Layout Margins — حاشیههای داخلی پیشفرض view (16pt در iOS، 20pt در iPadOS). برای UILayoutGuide میتوان directionalLayoutMargins سفارشی با در نظر گرفتن بومیسازی RIGHT-TO-LEFT تنظیم کرد. Auto Layout هنگام استفاده از safeAreaLayoutGuide در anchorها به طور خودکار safe area را در نظر میگیرد.
در دستگاههای دارای Dynamic Island (iPhone 14 Pro و جدیدتر) و Notch (iPhone X–13) Safe Area 44pt از بالا در حالت عمودی (59pt با Dynamic Island در حالت فعال) را مستثنی میکند. Home Indicator 34pt از پایین اضافه میکند. برای سازگاری صحیح، همه top-constraints باید به safeAreaLayoutGuide.topAnchor متصل شوند، نه به view.topAnchor. Bottom-constraints — به safeAreaLayoutGuide.bottomAnchor یا view.bottomAnchor با احتساب Home Indicator. در IT Sectr همه صفحات را روی شبیهسازهای iPhone SE (2022)، iPhone 14 Pro Max و iPad Pro 12.9″ آزمایش میکنیم — سه دستگاهی که همه انواع safe area را پوشش میدهند.
رایجترین اشتباهات هنگام کار با Auto Layout: translatesAutoresizingMaskIntoConstraints = false فراموش شده، تضاد Required constraints (اولویت 1000)، Ambiguous Layout (constraints ناکافی برای تعیین موقعیت)، Content Hugging Priority نادرست برای UILabel با متن چندخطی و مخلوط کردن leading/trailing با left/right anchors. Xcode 15+ مشکلات layout را در Runtime Issue Navigator نمایش میدهد و اصلاحات خودکار ارائه میدهد. برای طرحبندیهای پیچیده از Debug View Hierarchy استفاده کنید: برچسبهای زرد نشاندهنده ambiguous layout، قرمز — unsatisfiable هستند.
| خطا | علت | راهحل |
|---|---|---|
| translatesAutoresizingMaskIntoConstraints = true | Auto Layout برای view فعال نیست | برای همه viewهای برنامهنویسی false تنظیم کنید |
| Unsatisfiable Layout | تضاد Required (1000) constraints | اولویت یکی را به Default High (750) کاهش دهید |
| Ambiguous Layout | constraints کافی برای x/y/w/h نیست | constraint缺失 اضافه کنید یا intrinsic size را بررسی کنید |
| برش متن در UILabel | Content Hugging Priority پایینتر از رقیب | hugging priority را به 252+ افزایش دهید |
| مخلوط کردن anchorهای LTR/RTL | leadingAnchor با rightAnchor | فقط از leading/trailing برای پشتیبانی RTL استفاده کنید |
سوالات متداول
طراحی قابمحور مختصات ثابت x، y، width، height را برای هر عنصر تعیین میکند. Auto Layout از محدودیتهای ریاضی (constraints) استفاده میکند — روابط بین عناصر: «label.leading = button.trailing + 8». طراحی قابمحور با اندازه صفحه سازگار نمیشود؛ Auto Layout به طور خودکار موقعیتها را هنگام چرخش، Split View یا تغییر Dynamic Type دوباره محاسبه میکند.
UIStackView برای طرحبندیهای خطی بهینه است: ردیفها، ستونها، فرمها، لیست پارامترها. NSLayoutConstraint برای viewهای همپوشان، موقعیتیابی دقیق پیکسلی، انیمیشن سفارشی bounds و مواردی که توزیع فضا نابرابر است و توسط distribution UIStackView پوشش داده نمیشود ضروری است. در عمل 80٪ طرحبندیها با UIStackView و 20٪ با constraints دستی حل میشوند.
Content Hugging Priority (مقاومت در برابر کشیده شدن) — اولویتی که تعیین میکند عنصر چقدر در برابر افزایش اندازه خود فراتر از Intrinsic Content Size مقاومت میکند. مقدار پیشفرض — 251. اگر دو عنصر برای فضای خالی رقابت کنند، عنصر با hugging priority بالاتر در اندازه خود باقی میماند و دومی کشیده میشود. Compression Resistance Priority (پیشفرض 749) به طور مشابه برای فشردهسازی عمل میکند.
Auto Layout به طور خودکار با Dynamic Type سازگار میشود، اگر constraints از intrinsic content size برچسبها استفاده کنند. با افزایش اندازه فونت، UILabel گسترش مییابد و عناصر مجاور را از طریق constraints جابجا میکند. UIStackView با distribution = fillProportionally فضا را متناسب با intrinsic size جدید توزیع میکند. Safe Area و Layout Margins نیز تنظیمات دسترسپذیری را در نظر میگیرند.
Unsatisfiable Layout زمانی رخ میدهد که دو Required (priority = 1000) constraints با یکدیگر تضاد داشته باشند: مثلاً view.leading = superview.leading + 16 و view.trailing = superview.leading + 200 با superview به عرض 100pt. الگوریتم Cassowary نمیتواند راهحلی پیدا کند و برنامه با NSConstraintException crash میکند. راهحل — اولویت یکی از constraints متضاد را به Default High (750) کاهش دهید.
خلاصه
ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد
IT Sectr از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.