Layout Overview
With the Kotlin language itself covered, we now turn to building actual screens. Every screen
TrailLog shows — the trail list, the "add a new hike" form, a single trail's detail view — is,
underneath everything, a tree of View objects. This lesson covers that tree structure,
the main layout containers you'll reach for, how to size the views inside them, and the
density-independent unit Android uses for that sizing. It's the foundation the next several lessons
(View Binding, ConstraintLayout, RecyclerView) all build on.
The View / ViewGroup Hierarchy
Every visible thing on an Android screen is a View — a button, a text label, an image.
A ViewGroup is a special kind of View that can contain other Views (its
children) and arrange them — a ViewGroup is itself still a View, which is
what lets these nest arbitrarily deep. A screen's entire layout, then, is just a tree: a root
ViewGroup, containing child Views and possibly more nested ViewGroups, each
responsible for arranging whatever's inside it.
The Main Layout ViewGroups
| ViewGroup | What it's for |
|---|---|
ConstraintLayout | the modern, recommended default — positions each child relative to other children or to the parent's edges using constraints; covered in depth in ConstraintLayout |
LinearLayout | the simplest option — stacks children in a single row or a single column, in order |
FrameLayout | for stacking views directly on top of each other, or for holding a single child (like one Fragment's content) that fills the available space |
Worked Example: TrailLog's Trail-List Screen, at a High Level
Here's a simplified sketch of the actual layout behind TrailLog's trail-list screen: a
ConstraintLayout root holding a RecyclerView that fills the screen to show
every logged trail, plus a Floating Action Button anchored to the bottom-right corner for adding a
new one.
<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.recyclerview.widget.RecyclerView
android:id="@+id/trailListRecyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/addTrailFab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="16dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
Notice the RecyclerView is told to fill all available space while the
FloatingActionButton sizes itself to its own content and pins itself to a corner — which
is exactly what the next section's sizing keywords control.
Sizing Views: wrap_content, match_parent, and Fixed Values
| Value | Meaning |
|---|---|
wrap_content | the view sizes itself just large enough to fit its own content (text, an icon, etc.) |
match_parent | the view stretches to fill all the space its parent gives it |
a fixed value, e.g. 48dp | the view is exactly that size, regardless of its content or its parent |
Why dp, Not Raw Pixels
Android phones and tablets ship with wildly different screen densities — the same number of raw
pixels can represent a physically tiny area on a high-density screen and a much larger area on a
low-density one. If layouts were sized in raw pixels, a button that looked comfortably tappable on
one device could shrink to nearly invisible on another. dp (density-independent pixel)
is a unit that Android automatically scales based on the device's actual screen density, so a view
declared as 48dp ends up occupying roughly the same physical size —
the same number of millimeters on the actual screen — no matter which device it's running on.
That's why every measurement in the layout above (16dp margin, and so on) is expressed
in dp rather than a plain number.
From XML to Real Views: Inflation
The XML you write is just a description — it isn't the actual UI. At runtime, Android's
LayoutInflater reads that XML and "inflates" it: it walks the tree, creating a real
View/ViewGroup object in memory for every tag, wiring up the parent-child
relationships and attributes exactly as declared, and returns the finished object tree that
actually gets drawn to the screen.
findViewById().