Chains and Guidelines
Chains
A chain connects two or more views in the same axis. The first and last views in the chain are connected to the opposite ends of the parent. Chains distribute remaining space based on their style:
<!-- Spread chain — equal spacing between items -->
<TextView
android:id="@+id/label1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Item 1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@id/label2"
app:layout_constraintHorizontal_chainStyle="spread" />
<TextView
android:id="@+id/label2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Item 2"
app:layout_constraintStart_toEndOf="@id/label1"
app:layout_constraintEnd_toEndOf="parent" />
Chain styles:
| Style | Behavior |
|---|---|
spread |
Equal gaps between items and edges |
spread_inside |
Items pushed to edges, no gap at parent edges |
packed |
Items centered together with no gaps |
Weighted Chains
Add layout_constraintHorizontal_weight to views in a chain to distribute space proportionally (like LinearLayout weight):
<TextView
android:id="@+id/left"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintHorizontal_weight="2"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@id/right"
app:layout_constraintHorizontal_chainStyle="spread" />
<TextView
android:id="@+id/right"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintHorizontal_weight="1"
app:layout_constraintStart_toEndOf="@id/left"
app:layout_constraintEnd_toEndOf="parent" />
This gives left twice the space of right.
Guidelines
Guidelines are invisible lines that views can constrain to. They let you define responsive margins without hardcoding:
<!-- Vertical guideline at 25% from the left -->
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.25" />
<!-- Views constrain to the guideline -->
<TextView
android:id="@+id/label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toEndOf="@id/guideline"
app:layout_constraintTop_toTopOf="parent" />
Guideline types:
app:layout_constraintGuide_percent— percentage of parent size (0.0 to 1.0)app:layout_constraintGuide_begin— fixed offset from the start edgeapp:layout_constraintGuide_end— fixed offset from the end edge
Barriers
Barriers move dynamically based on the largest view they reference. Instead of constraining to a fixed guideline, you constrain to a barrier that shifts when content grows:
<!-- Barrier moves right of the tallest view -->
<androidx.constraintlayout.widget.Barrier
android:id="@+id/barrier"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:barrierDirection="end"
app:constraint_referenced_ids="name,email,phone" />
<!-- This view stays to the right of whichever is tallest -->
<TextView
android:id="@+id/editBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Edit"
app:layout_constraintStart_toEndOf="@id/barrier"
app:layout_constraintTop_toTopOf="@id/name" />
Use barriers when content is dynamic (localized text, user-generated content) and you can't predict which view will be the tallest.
Responsive Layouts with Constraints
Constrained Dimensions
Instead of fixed dp widths, constrain a view's width to a percentage of the parent or a ratio to its height:
<!-- 50% of parent width -->
<TextView
android:id="@+id/halfWidth"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintWidth_percent="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
Aspect Ratios
Force a view to maintain a specific width:height ratio:
<!-- Always 16:9 regardless of width -->
<ImageView
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintDimensionRatio="16:9"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
layout_constraintDimensionRatio works when at least one dimension is 0dp (match constraints). The ratio can be specified as width:height or as a float.
Horizontal and Vertical Bias
Bias positions a view between two constraints without changing the constraint structure:
<!-- Positioned 30% from the left constraint -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.3"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintVertical_bias="0.5" />
Bias defaults to 0.5 (centered). Values closer to 0 push left/top; values closer to 1 push right/bottom. Bias only takes effect when both opposing constraints are present.
Complete Responsive Layout Example
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- Top bar: 8dp from edges, anchored to top -->
<TextView
android:id="@+id/header"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="Dashboard"
android:textAppearance="?attr/textAppearanceHeadlineMedium"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:padding="16dp" />
<!-- Barrier below header for dynamic content -->
<androidx.constraintlayout.widget.Barrier
android:id="@+id/headerBarrier"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:barrierDirection="bottom"
app:constraint_referenced_ids="header" />
<!-- Card: 50% width, 16:9 ratio, starts at barrier -->
<com.google.android.material.card.MaterialCardView
android:id="@+id/card"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintWidth_percent="0.5"
app:layout_constraintDimensionRatio="4:3"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/headerBarrier"
app:layout_margin="8dp">
<!-- Card content -->
</com.google.android.material.card.MaterialCardView>
<!-- Info: fills remaining space to the right of card -->
<TextView
android:id="@+id/info"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="Details here"
app:layout_constraintStart_toEndOf="@id/card"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/card"
app:layout_constraintBottom_toBottomOf="@id/card"
app:layout_constraintVertical_bias="0.5"
android:padding="8dp" />
</androidx.constraintlayout.widget.ConstraintLayout>
This layout adapts to any screen size: the card stays 50% wide, the info fills the rest, and the header is always at the top.
Quiz
1. What does a spread chain do in ConstraintLayout?
2. When should you use a Barrier instead of a Guideline?
3. How does layout_constraintHorizontal_bias affect a view?
4. What does layout_constraintDimensionRatio require?
Flashcards
Question
What are the three chain styles in ConstraintLayout?
Click to reveal answer
Answer
spread (equal gaps everywhere), spread_inside (gaps between items only, no edge gaps), packed (all items centered together).
Question
What is the difference between a Guideline and a Barrier?
Click to reveal answer
Answer
Guideline is a fixed position (percent or dp offset). Barrier moves dynamically based on the largest view it references.
Question
When does layout_constraintHorizontal_bias take effect?
Click to reveal answer
Answer
Only when both horizontal constraints are set (e.g., start_toStartOf and end_toEndOf). Without opposing constraints, bias has nothing to interpolate.
Question
How do you set a 50% width constraint on a view?
Click to reveal answer
Answer
Set layout_width to 0dp and use app:layout_constraintWidth_percent="0.5". This constrains the view to half the parent width.
Revision Notes
Key Takeaways
- 1. Chains distribute space among connected views — spread, spread_inside, and packed are the three styles
- 2. Barriers shift dynamically with content size, making them ideal for localized or dynamic text
- 3. Aspect ratios require at least one 0dp dimension to compute the constrained dimension
- 4. Bias only takes effect when both opposing constraints are present
- 5. Guidelines provide fixed reference points; Barriers provide dynamic reference points
Interview Tips
- • Explain when you'd use a Barrier over a Guideline — dynamic content vs fixed positioning
- • Be ready to describe chain styles and when to use weighted chains vs spread
- • Know that aspect ratios need at least one 0dp dimension
- • Discuss how bias lets you create non-centered layouts without removing constraints
Cheat Sheet
ConstraintLayout Deep Dive Cheat Sheet
Chains:
- Connect first and last views to opposite parent edges
- Styles: spread, spread_inside, packed
- Weight: layout_constraintHorizontal_weight for proportional sizing
Guidelines:
- Invisible lines for consistent spacing
- Percent: layout_constraintGuide_percent (0.0–1.0)
- Fixed: layout_constraintGuide_begin/end (dp)
Barriers:
- Move based on the largest referenced view
- Use when content size is dynamic/unpredictable
- barrierDirection: start, end, top, bottom, left, right
Responsive techniques:
- layout_constraintWidth_percent for percentage widths
- layout_constraintDimensionRatio for aspect ratios
- layout_constraintHorizontal_bias for non-centered positioning
- Bias only works with opposing constraints
Key rule:
Every view needs at least one horizontal + one vertical constraint or it jumps to 0,0.