ConstraintLayout
ConstraintLayout is the layout Android recommends as the default container for most
screens, and it's what TrailLog's own screens are built on. Instead of nesting several
LinearLayouts inside each other to line things up, you describe where each view sits
relative to other views or to the parent, and the system solves the whole screen's positions in one
flat pass. This lesson builds up that idea with a full worked TrailLog example.
Why ConstraintLayout Is the Recommended Default
Before ConstraintLayout, a moderately complex screen often meant a LinearLayout containing
another LinearLayout containing a RelativeLayout, and so on. Each nested
layout adds another pass of measuring and positioning that the system has to work through before it can
draw the screen. ConstraintLayout's core promise is a single, flat view hierarchy: all
of a screen's views are direct children of one ConstraintLayout, with no nesting needed to
achieve complex arrangements. Fewer layout levels genuinely means less work for the system on every
measure and layout pass, which is why it's the recommended choice even for fairly simple screens.
The Core Idea: Constraints
A constraint ties one edge of a view to an edge of either the parent or another view.
Every view placed in a ConstraintLayout needs enough constraints to pin its position — at
minimum one horizontal and one vertical constraint, or it can end up snapped to the top-left corner.
The most common constraint attributes look like this:
app:layout_constraintTop_toTopOf="parent"— pin this view's top edge to the parent's top edge.app:layout_constraintTop_toBottomOf="@id/otherView"— pin this view's top edge just below another view's bottom edge.app:layout_constraintStart_toStartOf="parent"— pin this view's start edge to the parent's start edge (start/end instead of left/right so it works correctly in right-to-left languages).app:layout_constraintEnd_toEndOf="parent"— pin this view's end edge to the parent's end edge.
Worked Example: TrailLog's Trail Detail Screen
Here's the layout behind TrailDetailActivity: a photo at the top, the trail's name
constrained just below it, and the distance constrained below the name.
<!-- res/layout/activity_trail_detail.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">
<ImageView
android:id="@+id/trailPhoto"
android:contentDescription="Trail photo"
android:scaleType="centerCrop"
android:layout_width="0dp"
android:layout_height="220dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
<TextView
android:id="@+id/trailNameText"
android:textStyle="bold"
android:textSize="20sp"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
app:layout_constraintTop_toBottomOf="@id/trailPhoto"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
<TextView
android:id="@+id/trailDistanceText"
android:textColor="#666666"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:layout_marginStart="16dp"
app:layout_constraintTop_toBottomOf="@id/trailNameText"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
Notice the chain of relationships: the photo is pinned to the parent's top and both sides; the name
is pinned below the photo (toBottomOf="@id/trailPhoto"); and the distance is pinned below
the name. Three views, three positions, and not one of them is nested inside another — that's the flat
hierarchy ConstraintLayout is built around.
0dp: "Match Constraints" Sizing
Both trailPhoto and trailNameText above use
android:layout_width="0dp". Inside a ConstraintLayout, 0dp has a
special meaning distinct from wrap_content or match_parent: it tells the view
to stretch to fill whatever space its constraints leave available. trailPhoto
is constrained to both the parent's start and end, so with a width of 0dp it stretches
edge-to-edge; wrap_content there would just size the view to its natural content size and
ignore the space between the constraints, while match_parent would ignore the constraints
entirely and size itself to the parent's full width regardless of what it's constrained to. In practice:
reach for 0dp whenever a view should stretch between two constraints.
Chains: Distributing Several Views Evenly
When a row of views are all constrained to each other in sequence — the first to the second, the
second to the third, and so on — ConstraintLayout recognizes that as a chain, and lets
you control how the leftover space is distributed with
app:layout_constraintHorizontal_chainStyle (or the vertical equivalent) on the first view
in the chain. If TrailLog's detail screen had three stat chips — distance, date, and elevation — laid
out in a row, setting the chain style to "spread" would space them out evenly across the
width, "packed" would pull them together in the middle, and
"spread_inside" would push the first and last chips to the outer edges while spacing the
rest evenly between them.
Guidelines: An Invisible Alignment Reference
A Guideline is a line that exists purely for other views to constrain against — it's
never drawn on screen. It's useful when several views need to line up at a position that isn't tied to
any particular view, like "20% in from the left edge":
<androidx.constraintlayout.widget.Guideline
android:id="@+id/startGuideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.20" />
Any view can then constrain to @id/startGuideline exactly as it would to any other view's
edge. If TrailLog's detail screen later added a column of labels (Distance, Date, Notes), a single
guideline keeps all of them aligned without hardcoding the same margin on every one.
The Layout Editor: A Visual Alternative
Android Studio ships a visual Layout Editor that lets you drag views onto a canvas and
draw constraints by dragging from one edge to another, rather than typing every
app:layout_constraint... attribute by hand. It's a genuinely productive way to build
screens day to day. That said, everything the Layout Editor produces is exactly the XML shown in this
lesson — understanding that XML directly, which is this lesson's focus, is what lets you read, review,
and fix a layout confidently regardless of which tool wrote it.