ConstraintLayout یک ViewGroup بسیار قدرتمند جهت طراحی صفحات نرم افزارهای اندرویدی است که امکان ایجاد طرح های منعطف و کارآمد را برای شما فراهم می کند. ViewGroup ویژگی های بسیار منحصر به فردی دارد که امکان را برای شما فراهم می کند که با سادگی هرچه تمام تر و کمترین حجم کد نویسی لایوت های پیچیده و بزرگ را با سلسله مراتب کم (اکثرا صفر) پیاده سازی کنید.
در این مقاله قصد داریم چند تا از مهم ترین ویژگی های ConstraintLayout را بررسی کنیم. که در ادامه به آن ها می پردازیم
محدود کردن به یک خط راهنما
یکی از امکانات منحصر به فرد ConstraintLayout این هست که شما قادرید یک خط راهنما (guideline) به صورت عمودی یا افقی در طرحتان تعریف کنید و سایر المان های طرح تان را به آن متصل و محدود کنید، دقت کنید که این راهنما برای کاربران برنامه نامرئی خواهد بود و فقط در پیش نمایش اندروید استدیو قابل دیدن هست.
شما می توانید این راهنما را در داخل طرحتان بر اساس واحدهای dp یا درصد ، نسبت به لبه ConstraintLayout قرار دهید.
جهت فاصله از لبه ی آغازین (بالا در حالت افقی و سمت چپ در حالت عمودی) از کد :
app:layout_constraintGuide_begin="100dp"و جهت فاصله از لبه ی انتهایی (پایین در حالت افقی و سمت راست در حالت عمودی) از کد:
app:layout_constraintGuide_end="100dp"و در نهایت جهت تعیین فاصله با استفاده از درصد نسبت به لبه ی آغازین از کد :
app:layout_constraintGuide_percent="0.33"استفاده کنید. به این نکته دقت کنید که فقط یکی از سه حالت تعریف شده بالا را باید انتخاب کنید و در صورت استفاده از حالت سوم یک عدد اعشاری بین 0 تا 1 را وارد نمایید.
شکل 1- استفاده از خط راهنما (guideline)
در شکل 1 ما قصد داریم طرحی را پیاده سازی کنیم که در آن المان A در تمام حالات به اندازه یک سوم صفحه (33%) از لبه لایوت قرار بگیرد، برای پیاده سازی این طرح ابتدا باید یک راهنمای عمودی در 33 درصد نسبت به لایه اصلی به شکل زیر تعریف کرده و سپس المان A را به صورت زیر به انتهای خط راهنما متصل کنیم :
<?xml version="1.0" encoding="utf-8"?>
<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">
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.33" />
<TextView
android:layout_width="100dp"
android:layout_height="50dp"
android:background="@android:color/darker_gray"
android:text="A"
android:layout_marginStart="24dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@id/guideline"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
محدود کردن به یک مانع
همانند خطوط راهنما، مانع (Barrier) یک خط نامرئی هست که شما می توانید المان های طرحتان را به آن محدود کنید. از موانع زمانی استفاده می شود که شما قصد دارید مشابه شکل 2 یک المان (C) را به یک مجموعه از المان ها (A , B) محدود کنید و نه یک المان خاص دیگر.
شکل 2
زمانی که یک مانع تعریف می کنید، مانع مکان دقیق قرارگیری خودش را مشخص نمی کند و محل قرارگیری آن با توجه به المان هایی که با آن نسبت داده اید (A , B) تغییر می کند. در شکل2-الف طول المان A بیشتر از المان B است و Barrier در انتهای المان A قرار می گیرد و در شکل 2-ب طول المان B بیشتر از المان A است و Barrier در انتهای المان B قرار می گیرد و در هر دو حالت المان C در انتهای مانع قرار می گیرد.
برای پیاده سازی یک مانع شما باید المان هایی که می خواهید مانع به آن ارجاع داده شود را با کد "constraint_referenced_ids="A,B و محل قرارگیری مانع نسبت به این مراجع را با کد ""=app:barrierDirection برای مانع مشخص کنید. برای مثال قصد داریم شکل 2 را پیاده سازی کنیم. ابتدا المان های A ,B ,C و یک Barrier تعریف کرده و سپس A ,B را به مانع ارجاع می دهیم و جهت قرارگیری مانع را مشخص کرده و در آخر المان C را به مانع به صورت زیر متصل می کنیم:
<?xml version="1.0" encoding="utf-8"?>
<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">
<TextView
android:id="@+id/A"
android:layout_width="100dp"
android:layout_height="50dp"
android:layout_margin="16dp"
android:background="@android:color/darker_gray"
android:text="A"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/B"
android:layout_width="200dp"
android:layout_height="50dp"
android:layout_margin="16dp"
android:background="@android:color/darker_gray"
android:text="B"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/A"
app:layout_constraintVertical_bias="0.8" />
<androidx.constraintlayout.widget.Barrier
android:id="@+id/barrier"
android:layout_width="wrap_content"
android:layout_height="match_parent"
app:barrierDirection="end"
app:constraint_referenced_ids="A,B" />
<TextView
android:layout_width="100dp"
android:layout_height="50dp"
android:layout_marginStart="24dp"
android:background="@android:color/darker_gray"
android:text="C"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@id/barrier"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
استفاده از bias
زمانی که شما یک المان را از دو جهت محدود کرده باشید (و اندازه ی المان به صورت عددی ثابت یا "wrap content" تعریف شده باشد.) به صورت پیش فرض المان در وسط دو جهت محدود شده (50%) قرار می گیرد. جهت تغییر نسبت قرارگیری المان می توانید از کدهای دستوری layout_constraintHorizontal_bias برای حالت افقی و layout_constraintVertical_bias برای حالت عمودی استفاده کنید.
شکل 3- استفاده از bias در ConstraintLayout
در شکل3 ما قصد داریم طرحی را پیاده سازی کنیم که در آن محل قرار گیری ImageView در حالت افقی 20% و در حالت عمودی 80% از لبه های طرح اصلی قرار بگیرد، برای پیاده سازی این طرح کافیست layout_constraintHorizontal_bias و layout_constraintHorizontal_bias را برای ImageView وارد نماییم:
<?xml version="1.0" encoding="utf-8"?>
<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">
<ImageView
android:layout_width="100dp"
android:layout_height="50dp"
android:background="@android:color/darker_gray"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintHorizontal_bias="0.2"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.8" />
</androidx.constraintlayout.widget.ConstraintLayout>
تعیین نسبت المان با استفاده از ratio
گاهی برای المان هایی مانند تصویر شما نیاز دارید که نسبت طول و ارتفاع المان را فارغ از اندازه تصویر به یک نسبت مشخص برای مثال نسبت 16:9 یا 1:1 انتخاب کنید. برای پیاده سازی این امر باید از بین طول و ارتفاع المان یکی را مشخص کرده و به دیگری مقدار 0dp بدهیم و سپس با کد app:layout_constraintDimensionRatio نسبتی که می خواهیم را به المان بدهیم.
شکل 4 -نحوه ی نسبت دهی به المان
برای مثال در کد زیر ما یک ImageView در طرحمان تعریف کرده و مقدار طول آن را برابر با کل طرح قرار داده ایم و ارتفاع آن را برابر با 0dp قرار داده ایم و سپس نسبت 16:9 را با استفاده از کد app:layout_constraintDimensionRatio="16:9" به تصویر متن داده ایم. در این شرایط فارغ از اندازه صفحه نمایش این تصویر همواره با نسبت 16:9 نمایش داده خواهد شد.
<?xml version="1.0" encoding="utf-8"?>
<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">
<ImageView
android:layout_width="match_parent"
android:layout_height="0dp"
android:background="@android:color/darker_gray"
app:layout_constraintDimensionRatio="16:9"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>تعریف زنجیره و گروه های خطی
یکی دیگر از امکانات منحصر به فرد ConstraintLayout این است که به شما اجازه می دهد المان هایتان را همانند حلقه های یک زنجیر به صورت زنجیره تعریف کنید. Chain یا زنجیره، گروهی از المان ها است که با محدودیت های دو طرفه به یکدیگر مرتبط هستند.
برای تشکیل زنجیره ها در صورتی که می خواهید زنجیره ی عمودی تشکیل بدهید باید تمام المان های زنجیره را به ترتیب از بالا تا پایین به هم وصل کنید و برای تشکیل زنجیره ها در صورتی که می خواهید زنجیره افقی تشکیل بدهید باید تمام المان های زنجیره را به ترتیب از چپ به راست به هم وصل کنید. (مشابه شکل 5) و سپس در اولین المان مجموعه app:layout_constraintVertical_chainStyle را بیفزایید
شکل5- انواع زنجیره (chain) در ConstraintLayout
المان های درون یک زنجیره می تواند به صورت عمودی یا افقی با هم یک زنجیره را به یکی از حالات زیر تشکیل دهند.
حالت اول Spread
مطابق با شکل 5-1 این حالت که به صورت پیش فرض برای زنجیره ها فعال هست. المان ها با فاصله مساوی از هم در طرح توزیع می شوند.
برای پیاده سازی این حالت باید به صورت زیر عمل کنید:
<?xml version="1.0" encoding="utf-8"?>
<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">
<TextView
android:id="@+id/A"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:background="@android:color/darker_gray"
android:text="A"
app:layout_constraintBottom_toTopOf="@id/B"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="spread" />
<TextView
android:id="@+id/B"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:background="@android:color/darker_gray"
android:text="B"
app:layout_constraintBottom_toTopOf="@id/C"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/A" />
<TextView
android:id="@+id/C"
android:layout_width="100dp"
android:layout_height="50dp"
android:background="@android:color/darker_gray"
android:text="C"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/B" />
</androidx.constraintlayout.widget.ConstraintLayout>حالت دوم Spread inside
همان طور که در شکل5-1 مشاهده می کنید در این حالت اولین و آخرین المان بر روی لبه های لایوت قرار گرفته و بقیه به طور مساوی در لایوت توزیع می شوند.در مثال پایین ما سه المان A,B,C را دریک به صورت یک زنجیره Spread inside به هم متصل کرده ایم. تنها تفاوت کد نویسی این حالت با حالت قبل در این است که اولین المان مجموعه مقدار layout_constraintVertical_chainStyle را بهspread_inside تغییر می دهیم.
<?xml version="1.0" encoding="utf-8"?>
<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">
<TextView
android:id="@+id/A"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:background="@android:color/darker_gray"
android:text="A"
app:layout_constraintBottom_toTopOf="@id/B"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="spread_inside" />
<TextView
android:id="@+id/B"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:background="@android:color/darker_gray"
android:text="B"
app:layout_constraintBottom_toTopOf="@id/C"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/A" />
<TextView
android:id="@+id/C"
android:layout_width="100dp"
android:layout_height="50dp"
android:background="@android:color/darker_gray"
android:text="C"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/B" />
</androidx.constraintlayout.widget.ConstraintLayout>حالت سوم Weighted
تا قبل از معرفی این قابلیت در Constraint Layout برنامه نویسان تنها با استفاده از LinearLayout قادر به وزن دهی المان های یک طرح بودند اما اکنون همان طور که در شکل 5-3 مشاهده می کنید با تعریف المان ها به صورت یک زنجیره Weighted شما قادرید المان ها را به هر مقدار که مایلید وزن دهی کنید. برای انجام این کار باید بسته به اینکه می خواهید وزن دهی به صورت افقی یا عمودی باشد طول یا ارتفاع المان های زنجیره را برابر با 0dp (طول برای حالت افقی و ارتفاع برای حالت عمودی) قرار دهید و به هر یک از المان های زنجیره ویژگی زیر را بیفزایید.
برای وزن دهی افقی کد:
app:layout_constraintHorizontal_weight="10"برای وزن دهی عمودی کد:
app:layout_constraintVertical_weight="10"در مثال پایین ما سه المان A,B,C را دریک به صورت یک زنجیره Weighted به هم متصل کرده ایم و به هر کدام از المان ها به ترتیب وزن 10 و 20 و 30 را نسبت داده ایم.
<?xml version="1.0" encoding="utf-8"?>
<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">
<TextView
android:id="@+id/A"
android:layout_width="100dp"
android:layout_height="0dp"
android:background="@android:color/darker_gray"
android:text="A"
app:layout_constraintBottom_toTopOf="@id/B"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_weight="10" />
<TextView
android:id="@+id/B"
android:layout_width="200dp"
android:layout_height="0dp"
android:background="@android:color/darker_gray"
android:text="B"
app:layout_constraintBottom_toTopOf="@id/C"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/A"
app:layout_constraintVertical_weight="20" />
<TextView
android:id="@+id/C"
android:layout_width="100dp"
android:layout_height="0dp"
android:background="@android:color/darker_gray"
android:text="C"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/B"
app:layout_constraintVertical_weight="30" />
</androidx.constraintlayout.widget.ConstraintLayout>به این نکته توجه فرمایید که در زنجیره Weighted بر خلاف نوع زنجیره دیگر layout_constraintVertical_chainStyle را تعریف نکرده ایم و فقط با مقداردهی 0dp به ارتفاع المان ها و تعریف layout_constraintVertical_weight وزن المان ها را مشخص کرده ایم.
حالت چهارم Packed
همانطور که در شکل 5-4 مشاهده می کنید در حالت Packed تمام المان های زنجیره کاملا به هم می چسپند و در وسط لایوت قرار می گیرند. اگر نیاز داشتید زنجیره را بجای قرار گرفتن در وسط لایوت (50%) در نسبت دیگری قرار بدهید می توانید از bias که در همین مقاله توضیح داده شد (مورد سوم) استفاده کنید.
در مثال پایین ما سه المان A,B,C را دریک به صورت یک زنجیره Packed به هم متصل کرده ایم و با استفاده از "layout_constraintVertical_bias="0.3 تمام المان های زنجیره را در نسبت 30% عمودی از کل طرح قرار داده ایم.
<?xml version="1.0" encoding="utf-8"?>
<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">
<TextView
app:layout_constraintVertical_bias="0.3"
app:layout_constraintVertical_chainStyle="packed"
android:id="@+id/A"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:background="@android:color/darker_gray"
android:text="A"
app:layout_constraintBottom_toTopOf="@id/B"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/B"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:background="@android:color/darker_gray"
android:text="B"
app:layout_constraintBottom_toTopOf="@id/C"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/A" />
<TextView
android:id="@+id/C"
android:layout_width="100dp"
android:layout_height="50dp"
android:background="@android:color/darker_gray"
android:text="C"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/B" />
</androidx.constraintlayout.widget.ConstraintLayout>
جمع بندی
شرکت گوگل به عنوان توسعه دهنده سیستم عامل اندروید توجه ویژه ای به ConstraintLayout برای طراحی صفحات اندرویدی دارد و همواره امکانات و ویژگی های زیادی را در بروز رسانی های این لایوت اضافه می کند تا برنامه نویسان اندروید به سادگی هرچه تمام تر بتوانند طرح هایی با پیچیدگی بالا را پیاده سازی کنند که در این مقاله به مهم ترین آن ها پرداختیم .همچنین ConstraintLayout خود به تنهایی قادر به پیاده سازی انیمیشن ها نیز هست که در مقالات بعدی به سایر این ویژگی ها و نحوه پیاده سازی انیمیشن توسط ConstraintLayout خواهیم پرداخت. با ما همراه باشید. منبع: https://developer.android.com/training/constraint-layout
ممنونم علیرضا جان محتوای خوبی بود
عالی مهندس جان دست مریزاد
بسیار عالی
خسته نباشید
دمت گرم