ویژگی‌های منحصر به‏‏ فرد ConstraintLayout

دسته بندی: اندروید
زمان مطالعه: 15 دقیقه
۱۴ اسفند ۱۳۹۸

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) محدود کنید و نه یک المان خاص دیگر.

barrier شکل 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

چه امتیازی به این مقاله می دید؟
نویسنده علیرضا اسلمی

نظرات کاربران

حمیدرضا

عالی مهندس جان دست مریزاد

وحید گروسی

ممنونم علیرضا جان محتوای خوبی بود

ارسال دیدگاه
خوشحال میشیم دیدگاه و یا تجربیات خودتون رو با ما در میون بذارید :