ConstraintLayout — چیست، محدودیت‌ها و سلسله‌مراتب تخت

نویسنده: IT Sectr منتشر شده: 2026-02-24 زمان مطالعه: 10 دقیقه

ما بررسی می‌کنیم که ConstraintLayout چیست — یک سیستم موقعیت‌یابی منعطف برای Android که به شما امکان می‌دهد سلسله‌مراتب تخت viewها را با استفاده از محدودیت‌ها (constraints) به جای LinearLayout و RelativeLayout تو در تو بسازید. ConstraintLayout مشکل «تودرتوی جهنمی» layout (layout nesting hell) را حل می‌کند، عمق سلسله‌مراتب را به یک سطح کاهش می‌دهد و رندر صفحه را سرعت می‌بخشد. این کتابخانه بخشی از Jetpack است و از Android 2.3 (API 9) به بعد از طریق support-library در دسترس است. مکانیزم‌های اصلی در مستندات رسمی Android توضیح داده شده‌اند.

نکات اصلی

  • سلسله‌مراتب تخت — ConstraintLayout به شما امکان می‌دهد رابط کاربری با هر پیچیدگی را بدون کانتینرهای تو در تو بسازید که onMeasure و onLayout را ۲ تا ۳ برابر سریع‌تر می‌کند.
  • محدودیت‌ها — موقعیت‌یابی عناصر از طریق اتصال لبه‌ها (layout_constraintLeft_toRightOf, layout_constraintTop_toBottomOf) به والد یا viewهای دیگر.
  • Chain و Guideline — زنجیره‌ها عناصر را به طور مساوی یا بر اساس وزن توزیع می‌کنند؛ راهنماها (Guideline) فاصله‌های تناسبی را به درصد تعیین می‌کنند.
  • Barrier و Group — مانع به طور پویا با اندازه گروه عناصر تنظیم می‌شود؛ Group قابلیت مشاهده چندین view را یکباره مدیریت می‌کند.
  • MotionLayout — زیرکلاس ConstraintLayout برای انیمیشن انتقال بین حالت‌های محدودیت‌ها با پشتیبانی KeyFrame.

ConstraintLayout چیست؟

ConstraintLayout — یک ViewGroup از کتابخانه AndroidX ConstraintLayout است که برای ایجاد رابط‌های منعطف و کارآمد از طریق محدودیت‌های اعلامی (constraints) طراحی شده است. برخلاف LinearLayout که عناصر را در یک خط قرار می‌دهد یا RelativeLayout که نسبت به همسایگان موقعیت‌یابی می‌کند، ConstraintLayout به شما امکان می‌دهد هر عنصر را همزمان نسبت به هر عنصر دیگر و والد متصل کنید.

این کتابخانه در Google I/O 2016 به عنوان راه‌حلی برای تسریع رندر صفحات پیچیده معرفی شد. مشکل کلیدی که ConstraintLayout حل می‌کند تودرتوی layout است. هر ViewGroup تو در تو حداقل دو بار measure و یک بار layout اضافه می‌کند. صفحه‌ای با ۴ سطح تودرتو ۸ بار measure اجرا می‌کند؛ ConstraintLayout با همان قابلیت — فقط ۲ بار بر اساس داده‌های Google (Android Performance Blog, 2017)، جایگزینی سه LinearLayout تو در تو با یک ConstraintLayout زمان onMeasure را ۴۰٪ کاهش می‌دهد.

نسخه فعلی ConstraintLayout 2.1.4 به طور پایدار روی Android 2.3+ (API 9) از طریق AndroidX کار می‌کند. در نسخه ۲.۰، موقعیت‌یابی دایره‌ای، Flow (انتقال خودکار عناصر) و پشتیبانی MotionLayout اضافه شد. ConstraintLayout برای درک توسعه مدرن Android ضروری است — در Jetpack Compose به عنوان مفهوم اصلی اصلاح‌کننده‌ها، در قالب‌های پیش‌فرض Android Studio و در Material Design 3 استفاده می‌شود.

سلسله‌مراتب تخت چگونه کار می‌کند

سلسله‌مراتب تخت ConstraintLayout به این معنی است که همه Viewهای فرزند در یک سطح تودرتو قرار دارند. به جای قرار دادن عنصر A در LinearLayout و سپس LinearLayout در RelativeLayout، همه عناصر مستقیماً به ConstraintLayout والد یا به یکدیگر از طریق ویژگی‌ها متصل می‌شوند. این مزایا را به همراه دارد: مصرف حافظه کمتر (هر ViewGroup یک شیء در Java heap است)، سرعت بیشتر layout pass (فراخوانی‌های بازگشتی کمتر)، رفتار قابل پیش‌بینی‌تر در تغییر اندازه صفحه.

سیستم محدودیت‌ها: اتصالات، bias و حاشیه

محدودیت — ارتباط بین لبه یک View (یا مرکز آن) و لبه View دیگر یا والد است. هر View می‌تواند تا ۸ محدودیت داشته باشد: چپ، بالا، راست، پایین، start، end، baseline و مرکز. حداقل برای موقعیت‌یابی دو محدودیت عمود بر هم کافی است (مثلاً بالا + چپ).

فرمت ویژگی: app:layout_constraint[منبع]_to[هدف]Of="[id]" — که منبع لبه متصل‌شونده است (Left, Right, Top, Bottom, Start, End, Baseline)، هدف لبه مقصد است. مثال: app:layout_constraintTop_toBottomOf="@+id/header" به معنای «مرز بالایی عنصر فعلی به مرز پایینی عنصر header متصل است». برای اتصال به والد از id parent استفاده می‌شود.

Bias (انحراف) — پارامتری که با وجود محدودیت‌های متضاد (left + right یا top + bottom) کار می‌کند. مقدار از ۰ تا ۱: ۰ — به لبه چپ/بالا چسبیده، ۰.۵ — در مرکز، ۱ — به لبه راست/پایین. ویژگی‌ها: layout_constraintHorizontal_bias (۰.۰–۱.۰) و layout_constraintVertical_bias. حاشیه با android:layout_margin* استاندارد تعیین می‌شود، اما محدودیت و حاشیه مستقل عمل می‌کنند: حاشیه فاصله از محدودیت است، نه از View مجاور.

موقعیت‌یابی درصدی

از ConstraintLayout 1.1+ به بعد، اندازه‌های درصدی از طریق layout_constraintWidth_percent و layout_constraintHeight_percent پشتیبانی می‌شوند. مقدار ۰.۳ به معنای ۳۰٪ از عرض/ارتفاع والد است. در ترکیب با bias، این امکان ایجاد layoutهای تطبیقی بدون برنامه‌نویسی را فراهم می‌کند.

Chains و Guidelines: زنجیره‌ها و راهنماها

Chain (زنجیره) — گروهی از دو یا چند View است که با محدودیت‌های دوطرفه متصل شده‌اند (A به B و B به A). زنجیره‌ها فضا را بین عناصر به طور خودکار در یکی از حالت‌های زیر توزیع می‌کنند: spread (مساوی با در نظر گرفتن حاشیه)، spread_inside (مساوی، عناصر کناری بدون فاصله از لبه‌ها)، packed (عناصر به هم چسبیده با bias مشترک). حالت با ویژگی app:layout_constraintHorizontal_chainStyle یا layout_constraintVertical_chainStyle تعیین می‌شود.

Guideline (راهنما) — یک View کمکی است که در زمان اجرا نامرئی است اما خطی را برای اتصال تعیین می‌کند. Guideline می‌تواند افقی یا عمودی باشد، با موقعیت‌یابی در dp، درصد (app:layout_constraintGuide_percent) یا با فاصله از لبه (app:layout_constraintGuide_begin/end). راهنماها برای layoutهای تطبیقی ضروری هستند — مثلاً برای تقسیم صفحه به دو نیمه مساوی بدون توجه به اندازه دستگاه.

بر اساس داده‌های Google I/O 2017، زنجیره‌های spread_inside ۱۵–۲۰٪ کارآمدتر از LinearLayoutهای تو در تو با weight هستند، زیرا از اندازه‌گیری مضاعف measure که برای محاسبه weight لازم است جلوگیری می‌کنند.

Barrier، Group و کمک‌کننده‌های مجازی

Barrier (مانع) — یک View مجازی است که به طور پویا موقعیت خود را با اندازه گروه عناصر تنظیم می‌کند. برخلاف Guideline با موقعیت ثابت، Barrier توسط عریض‌ترین عنصر گروه «هل داده می‌شود». مثلاً اگر عنوان و توضیحی با طول نامشخص دارید، Barrier متصل به لبه راست عریض‌ترین متن به شما امکان می‌دهد آیکون را بلافاصله بعد از آنها قرار دهید. ویژگی‌ها: app:barrierDirection (left, right, top, bottom, start, end) و app:constraint_referenced_ids (لیست idهای جدا شده با کاما).

Group — یک کانتینر مجازی است که قابلیت مشاهده چندین View را به طور همزمان مدیریت می‌کند. به جای فراخوانی setVisibility برای هر عنصر به طور جداگانه، کافی است قابلیت مشاهده یک Group را تغییر دهید. Group روی موقعیت‌یابی تأثیر نمی‌گذارد — فقط روی قابلیت مشاهده. Flow — یک کمک‌کننده مجازی برای ایجاد layoutهای «جاری»: عناصر در صورت کمبود فضا به طور خودکار به سطر/ستون جدید منتقل می‌شوند، مانند متن در یک پاراگراف. Flow از wrapMode: none، chain و aligned پشتیبانی می‌کند.

این ابزارها (Barrier, Group, Flow, Guideline) کمک‌کننده‌های مجازی نامیده می‌شوند زیرا در معنای کلاسیک View نیستند — در سلسله‌مراتب جا نمی‌گیرند و در فوکوس یا رویدادهای لمسی شرکت نمی‌کنند. هدف آنها ساده‌سازی نگهداری layoutهای پیچیده بدون افزودن کانتینرهای تو در تو است.

مثال‌ها: XML و Kotlin

مثال ۱: فرم پایه با محدودیت‌ها

فرم ورود ساده با فیلد ایمیل، رمز عبور و دکمه. همه عناصر به جز دکمه به parent متصل هستند — دکمه زیر فیلد رمز عبور قرار دارد. از سلسله‌مراتب تخت استفاده شده است — هر سه عنصر در یک سطح.

xml
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.google.android.material.textfield.TextInputLayout
        android:id="@+id/email_input"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        android:layout_marginTop="32dp"
        android:layout_marginHorizontal="16dp" />

    <com.google.android.material.textfield.TextInputLayout
        android:id="@+id/password_input"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toBottomOf="@+id/email_input"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        android:layout_marginTop="16dp"
        android:layout_marginHorizontal="16dp" />

    <Button
        android:id="@+id/login_button"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toBottomOf="@+id/password_input"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        android:layout_marginTop="24dp"
        android:layout_marginHorizontal="16dp"
        android:text="ورود" />

</androidx.constraintlayout.widget.ConstraintLayout>

همه عناصر عرض ۰dp (match_constraint) دارند، یعنی از start تا end محدودیت با در نظر گرفتن حاشیه افقی کشیده می‌شوند. این معادل match_parent با حاشیه است، اما بدون تودرتو.

مثال ۲: زنجیره با spread_inside

سه دکمه که به طور مساوی در افق با فاصله از لبه‌ها توزیع شده‌اند. زنجیره spread_inside دکمه‌های کناری را در لبه‌ها و دکمه وسط را در مرکز بین آنها قرار می‌دهد.

xml
<Button
    android:id="@+id/btn_left"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toLeftOf="@+id/btn_center"
    android:text="چپ" />

<Button
    android:id="@+id/btn_center"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:layout_constraintLeft_toRightOf="@+id/btn_left"
    app:layout_constraintRight_toLeftOf="@+id/btn_right"
    android:text="مرکز" />

<Button
    android:id="@+id/btn_right"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:layout_constraintLeft_toRightOf="@+id/btn_center"
    app:layout_constraintRight_toRightOf="parent"
    android:text="راست" />

زنجیره زمانی به طور خودکار ایجاد می‌شود که عناصر محدودیت‌های دوطرفه داشته باشند. حالت spread_inside در هر عنصر زنجیره از طریق app:layout_constraintHorizontal_chainStyle="spread_inside" تنظیم می‌شود. این کار نیاز به استفاده از LinearLayout با weightSum و layout_weight را از بین می‌برد.

مثال ۳: Guideline برای layout متقارن

ایجاد دو ستون مساوی از طریق Guideline عمودی روی ۵۰٪. عنصر چپ به لبه چپ parent و با لبه راست به guideline متصل است؛ عنصر راست — با لبه چپ به guideline و به لبه راست parent.

xml
<androidx.constraintlayout.widget.Guideline
    android:id="@+id/gl_midpoint"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    app:layout_constraintGuide_percent="0.5" />

<TextView
    android:id="@+id/left_card"
    android:layout_width="0dp"
    android:layout_height="0dp"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toLeftOf="@+id/gl_midpoint"
    android:layout_margin="8dp"
    android:background="@color/card_background" />

<TextView
    android:id="@+id/right_card"
    android:layout_width="0dp"
    android:layout_height="0dp"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintLeft_toRightOf="@+id/gl_midpoint"
    app:layout_constraintRight_toRightOf="parent"
    android:layout_margin="8dp"
    android:background="@color/card_background" />

Guideline با درصد ۰.۵ به طور خودکار با عرض صفحه تنظیم می‌شود. در تبلت و تلفن، نسبت ستون‌ها ۵۰/۵۰ باقی می‌ماند. برای نام‌گذاری چپ/راست از ویژگی‌های start/end برای سازگاری RTL استفاده کنید.

مقایسه: ConstraintLayout در مقابل LinearLayout در مقابل RelativeLayout

جدول مقایسه سه ViewGroup اصلی برای توسعه Android: ConstraintLayout، LinearLayout و RelativeLayout. معیارها: انعطاف‌پذیری، کارایی، پیچیدگی کد و حوزه‌های کاربرد.

ویژگیConstraintLayoutLinearLayoutRelativeLayout
تودرتوتخت (یک سطح)برای layoutهای پیچیده نیاز به تودرتو داردیک سطح اما انعطاف محدود
کارایی measure۲ بار (~۴۰٪ سریع‌تر)۴+ بار با weight۲ بار
اندازه‌های درصدیبله (guide_percent, width_percent)فقط از طریق weight/frameخیر
پشتیبانی RTLداخلی (start/end)داخلیاز طریق start/end (API 17+)
Barrier/Group/Flowبله (کمک‌کننده‌های مجازی)خیرخیر
انیمیشن MotionLayoutبلهخیرخیر
زمان استفادههمه layoutهای پیچیده، صفحه‌های با >۵ عنصرلیست‌های ساده یک‌جهته، ردیف‌های دکمهlayoutهای نسبی ساده (از کد قدیمی)

بر اساس داده‌های Android Vitals (Google, 2025)، برنامه‌هایی که از ConstraintLayout به عنوان کانتینر اصلی استفاده می‌کنند، به طور متوسط ۱۸٪ فریم‌های jank کمتری در رندر صفحات پیچیده نسبت به برنامه‌های با LinearLayoutهای تو در تو نشان می‌دهند. در IT Sectr ما در سال ۲۰۱۸ به ConstraintLayout به عنوان استاندارد برای همه layoutهای XML تغییر مکان دادیم — این کار میانگین عمق سلسله‌مراتب صفحه را از ۴.۲ به ۱.۸ سطح کاهش داد و توسعه فرم‌های جدید را ۲۵٪ سرعت بخشید.

سوالات متداول

تفاوت بین match_parent و ۰dp (match_constraint) در ConstraintLayout چیست؟

match_parent در ConstraintLayout مانند معمول کار می‌کند — View را تا اندازه والد می‌کشد. ۰dp (match_constraint) به این معنی است که اندازه View از محدودیت‌ها محاسبه می‌شود: اگر محدودیت‌های چپ و راست با حاشیه تنظیم شده باشند، عرض = parent — marginLeft — marginRight. تفاوت در رفتار: match_parent bias را نادیده می‌گیرد و ممکن است در هنگام انیمیشن از مرزها خارج شود؛ match_constraint به درستی همه محدودیت‌ها را در نظر می‌گیرد و توسط Google به عنوان حالت اصلی برای ConstraintLayout توصیه می‌شود.

چگونه با ConstraintLayout یک layout تطبیقی برای تبلت بسازیم؟

از ترکیب زیر استفاده کنید: اندازه‌های درصدی (layout_constraintWidth_percent) برای عناصری که باید بخشی از صفحه را اشغال کنند؛ Guideline با درصد برای تقسیم صفحه به مناطق؛ Barrier برای موقعیت‌یابی نسبت به محتوای پویا؛ Flow با wrapMode برای انتقال کارت‌ها به سطر جدید. رویکرد جایگزین — استفاده از SlidingPaneLayout در ترکیب با ConstraintLayout برای رابط‌های master-detail در تبلت‌ها.

آیا می‌توان از ConstraintLayout در Jetpack Compose استفاده کرد؟

Jetpack Compose از ConstraintLayout به عنوان ViewGroup استفاده نمی‌کند، اما نسخه Compose ConstraintLayout (androidx.constraintlayout:constraintlayout-compose) را با همان API در Kotlin DSL ارائه می‌دهد: createRefFor()، constrainAs()، linkTo()، chain()، guideFrom(). این برای layoutهای پیچیده‌ای که توصیف آنها از طریق Column/Row دشوارتر است مفید می‌باشد. با این حال، در Compose توصیه می‌شود با Column/Row/Box شروع کنید و فقط زمانی که به موقعیت‌یابی‌های نسبی پیچیده نیاز دارید به ConstraintLayout بروید.

چگونه همپوشانی عناصر در ConstraintLayout را دیباگ کنیم؟

در Android Studio Layout Inspector را باز کنید (Tools → Layout Inspector)، برنامه در حال اجرا را انتخاب کنید و روی عنصر مشکل‌دار بروید. همه محدودیت‌ها، حاشیه‌ها، padding و bias را در نمای سه‌بعدی خواهید دید. برای XML از پنل Design در ویرایشگر layout استفاده کنید — تداخل محدودیت‌ها را زرد و عدم وجود محدودیت را قرمز نشان می‌دهد. در کد بررسی کنید که هر View دو محدودیت عمود بر هم دارد، در غیر این صورت عنصر در (۰,۰) قرار می‌گیرد.

خلاصه

  • ConstraintLayout — ViewGroup برای سلسله‌مراتب تخت layoutهای Android از طریق محدودیت‌های اعلامی که عمق تودرتو را به ۱ سطح کاهش می‌دهد.
  • سیستم محدودیت‌ها — اتصال لبه‌ها به parent یا Viewهای دیگر، bias برای انحراف، اندازه‌های درصدی برای تطبیق‌پذیری.
  • Chains — زنجیره‌هایی با حالت‌های spread / spread_inside / packed برای توزیع عناصر بدون کانتینرهای تو در تو.
  • Guideline و Barrier — راهنماها (ثابت و درصدی) و موانع پویا برای موقعیت‌یابی منعطف.
  • کمک‌کننده‌های مجازی — Group (مدیریت قابلیت مشاهده)، Flow (انتقال خودکار)، MotionLayout (انیمیشن).
  • کارایی — ۴۰٪ سریع‌تر از LinearLayoutهای تو در تو، ۱۸٪ فریم‌های jank کمتر.
  • انتخاب — ConstraintLayout برای صفحه‌های پیچیده، LinearLayout برای ردیف‌های ساده، RelativeLayout فقط در کد قدیمی.

ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد

IT Sectr از سال 2017 برنامه‌های iOS و Android را برای استارتاپ‌ها و کسب‌وکارها ایجاد می‌کند. ما به شما مشاوره می‌دهیم و بهترین راه‌حل را پیشنهاد خواهیم کرد.

بحث درباره پروژه

همچنین بخوانید