Android Layout Types – Visual Guide
Android Layouts — Deep Dive
Side-by-side XML & UI · Attributes · Examples · When to use each
// Key Attributes
android:orientation
"vertical" | "horizontal"
Direction children are stacked. Default is horizontal.
android:layout_weight
0, 1, 2, ... (integer)
Divides remaining space proportionally. weight=1 each = equal split.
android:gravity
center | start | end | top | bottom
How content inside the LinearLayout is aligned.
android:layout_gravity
center | start | end | center_horizontal
How this child aligns inside its parent LinearLayout.
android:layout_margin
8dp, 16dp, ... (dimension)
Space outside the view. Variants: marginTop, marginStart, etc.
android:padding
8dp, 16dp, ... (dimension)
Space inside the view between border and content.
// Examples
This is the most classic use of LinearLayout. orientation="vertical" stacks every child from top to bottom. Each view gets the width of the parent (match_parent) and only as much height as it needs (wrap_content). Margins add breathing room between elements.
activity_login.xml
<!-- Root: vertical LinearLayout -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="24dp"
android:gravity="center_horizontal">
<!-- App Logo -->
<ImageView
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_marginBottom="24dp"
android:src="@drawable/logo" />
<!-- Title -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Welcome Back"
android:textSize="24sp"
android:textStyle="bold"
android:layout_marginBottom="24dp" />
<!-- Email input -->
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Email address"
android:inputType="textEmailAddress"
android:layout_marginBottom="12dp" />
<!-- Password input -->
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Password"
android:inputType="textPassword"
android:layout_marginBottom="20dp" />
<!-- Login button (full width) -->
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="LOG IN" />
</LinearLayout>
Preview
🔐
Welcome BackTextView · textSize=24sp · bold
Email address EditText · inputType=email
Password •••EditText · inputType=password
LOG INButton · width=match_parent
orientation: vertical ↓
Each child stacks below the previous.
gravity="center_horizontal" centers the logo & title.
Using orientation="horizontal" with layout_weight is a powerful pattern. When you set a child's width to
0dp and give it a weight, Android divides the total width proportionally. Here, three buttons each get exactly ⅓ of the space — no math needed!
bottom_nav.xml
<!-- Horizontal LinearLayout -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="56dp"
android:orientation="horizontal"
android:background="@color/surface">
<!-- Home tab: width=0dp, weight=1 = 33% -->
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="vertical"
android:gravity="center">
<ImageView android:src="@drawable/ic_home" />
<TextView android:text="Home" />
</LinearLayout>
<!-- Search tab: weight=1 = 33% -->
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="vertical"
android:gravity="center">
<ImageView android:src="@drawable/ic_search" />
<TextView android:text="Search" />
</LinearLayout>
<!-- Profile tab: weight=1 = 33% -->
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="vertical"
android:gravity="center">
<ImageView android:src="@drawable/ic_profile" />
<TextView android:text="Profile" />
</LinearLayout>
</LinearLayout>
Preview
[ Screen Content ]
🏠
Home
weight=1 (33%)
🔍
Search
weight=1 (33%)
👤
Profile
weight=1 (33%)
Key trick: Set
layout_width="0dp" + layout_weight="1" on each child to divide space equally.
// Key Attributes
android:layout_below
"@id/viewName"
Places this view directly below the referenced view.
android:layout_toRightOf
"@id/viewName"
Places this view to the right of the referenced view. Use toEndOf for RTL support.
android:layout_alignParentTop
"true" | "false"
Pins top edge to the parent's top edge.
android:layout_alignParentBottom
"true" | "false"
Pins bottom edge to the parent's bottom edge. Great for fixed footers.
android:layout_centerInParent
"true" | "false"
Centers this view both horizontally and vertically within the parent.
android:layout_alignBottom
"@id/viewName"
Aligns this view's bottom edge with the bottom edge of another view.
// Examples
RelativeLayout shines for asymmetric layouts. Here the avatar is pinned to the left, the message bubble is placed toRightOf the avatar, and the timestamp sits below the bubble aligned to its right. Each element references another by ID.
item_message.xml
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="8dp">
<!-- Avatar: pinned to start -->
<ImageView
android:id="@+id/avatar"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true" />
<!-- Bubble: to the right of avatar -->
<TextView
android:id="@+id/message"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toEndOf="@id/avatar"
android:layout_marginStart="8dp"
android:maxWidth="200dp"
android:text="Hey! How are you?"
android:background="@drawable/bubble_bg"
android:padding="10dp" />
<!-- Time: below bubble, aligned end -->
<TextView
android:id="@+id/timestamp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/message"
android:layout_alignEnd="@id/message"
android:layout_marginTop="2dp"
android:text="10:42 AM"
android:textSize="10sp"
android:textColor="@color/muted" />
</RelativeLayout>
Preview
👤
alignParentStart
Hey! How are you?
toEndOf @avatar
10:42 AM
below @msg, alignEnd
I'm doing great! 😊
10:43 AM ✓✓
Views reference each other by
@id/. Order in XML matters — reference only views already defined above.
// Key Attributes
app:layout_constraintTop_toTopOf
"parent" | "@id/view"
Aligns this view's top to another's top. Use "parent" to anchor to screen edge.
app:layout_constraintStart_toEndOf
"@id/view"
Places this view's start edge at another view's end — i.e., to the right of it.
app:layout_constraintHorizontal_bias
0.0 to 1.0
0.5 = centered. 0.0 = fully left. 1.0 = fully right. Works with both sides constrained.
app:layout_constraintWidth_percent
0.0 to 1.0
Set width as % of parent (use with layout_width="0dp").
app:layout_constraintDimensionRatio
"16:9" | "1:1" | "H,3:1"
Lock aspect ratio. e.g., "16:9" makes height = width * 9/16.
app:layout_constraintCircle
"@id/view"
Position this view at an angle and radius from another view's center.
// Examples
This example shows how ConstraintLayout connects everything in a flat hierarchy with no nesting. The avatar is centered horizontally and biased toward the top. The name sits below the avatar, constrained to it. The bio is below the name. The button is at the bottom of the screen. All in one level!
fragment_profile.xml
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- Avatar: centered, biased to top 30% -->
<ImageView
android:id="@+id/avatar"
android:layout_width="80dp"
android:layout_height="80dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintVertical_bias="0.25" />
<!-- Name: below avatar, centered -->
<TextView
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Sarah Connor"
android:textSize="20sp"
android:textStyle="bold"
android:layout_marginTop="12dp"
app:layout_constraintTop_toBottomOf="@id/avatar"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
<!-- Bio: below name -->
<TextView
android:id="@+id/bio"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="Android developer & coffee lover ☕"
android:layout_marginTop="6dp"
android:layout_marginHorizontal="32dp"
android:gravity="center"
app:layout_constraintTop_toBottomOf="@id/name"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
<!-- Button: pinned to bottom -->
<Button
android:id="@+id/followBtn"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="Follow"
android:layout_marginHorizontal="24dp"
android:layout_marginBottom="24dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
Preview
👩
bias=0.25 (top 25%)
Sarah Connor
below @avatar
Android developer & coffee lover ☕
width=0dp (fill)
Follow
constraintBottom_toBottomOf=parent
Every view has at least 2 constraints (one horizontal, one vertical). No nesting needed — all 4 views are direct children.
// Key Attributes
android:layout_gravity
center | top | bottom | start | end | top|end ...
Positions a child within the FrameLayout. Can combine values with | (pipe).
android:foreground
"@drawable/ripple" | @color/overlay
Draws a drawable on top of all children — useful for ripple effects.
android:measureAllChildren
"true" | "false"
If true, measures all children even GONE ones (affects wrap_content size).
// Examples
A classic FrameLayout use: an ImageView as the base layer, a ProgressBar centered on top (shown while loading), and a badge TextView anchored to the top-right corner using
layout_gravity="top|end". All three are siblings — no nesting.
item_photo.xml
<FrameLayout
android:layout_width="match_parent"
android:layout_height="200dp">
<!-- Layer 0: Base image (drawn first/bottom) -->
<ImageView
android:id="@+id/photo"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:src="@drawable/photo" />
<!-- Layer 1: Dark gradient scrim -->
<View
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/gradient_scrim" />
<!-- Layer 2: Loading spinner (center, hidden after load) -->
<ProgressBar
android:id="@+id/spinner"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:visibility="gone" />
<!-- Layer 3: Caption at bottom -->
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:padding="12dp"
android:text="Golden Gate Bridge"
android:textColor="#FFFFFF"
android:textSize="16sp" />
<!-- Layer 4 (top): Badge in corner -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="top|end"
android:layout_margin="8dp"
android:text=" ❤️ 142 "
android:background="@drawable/pill_bg"
android:textColor="#fff" />
</FrameLayout>
Preview — Z-Order (bottom → top)
Think of FrameLayout like Photoshop layers. XML order = Z-order. Last child in XML = drawn on top.
One of the most important uses of FrameLayout: hosting fragments. A FrameLayout with an ID becomes the slot where your NavController swaps fragments in and out. The layout itself is just an empty placeholder.
activity_main.xml
<LinearLayout
android:orientation="vertical">
<!-- Toolbar at the top -->
<Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize" />
<!-- Fragment container: fills remaining space -->
<FrameLayout
android:id="@+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
</LinearLayout>
// In MainActivity.kt:
supportFragmentManager.beginTransaction()
.replace(R.id.fragment_container, HomeFragment())
.commit()
Preview
← MyApp Toolbar
FrameLayout
id: fragment_container
🔄
fragments swap
in/out here
in/out here
// Key Attributes
android:stretchColumns
"0", "1", "*" (all)
Which columns stretch to fill remaining width. "*" stretches all.
android:shrinkColumns
"0", "1,2", "*"
Which columns can shrink if content overflows.
android:layout_column
0, 1, 2, ... (integer)
On a cell: which column to place this cell in (can skip columns).
android:layout_span
2, 3, ... (integer)
On a cell: span this many columns. Like HTML's colspan.
// Examples
The calculator layout is perfect for TableLayout. 4 rows of 4 buttons each. The bottom "0" button uses
layout_span="2" to span two columns. stretchColumns="*" makes all columns fill the available width equally.
layout_calculator.xml
<TableLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:stretchColumns="*">
<!-- Display Row -->
<TableRow>
<TextView
android:layout_span="4"
android:text="1,234"
android:textSize="32sp"
android:gravity="end"
android:padding="16dp" />
</TableRow>
<!-- Row 1: 7 8 9 ÷ -->
<TableRow>
<Button android:text="7" />
<Button android:text="8" />
<Button android:text="9" />
<Button android:text="÷"
android:textColor="@color/operator" />
</TableRow>
<!-- Row 2: 4 5 6 × -->
<TableRow>
<Button android:text="4" />
<Button android:text="5" />
<Button android:text="6" />
<Button android:text="×"
android:textColor="@color/operator" />
</TableRow>
<!-- Row 3: 1 2 3 − -->
<TableRow>
<Button android:text="1" />
<Button android:text="2" />
<Button android:text="3" />
<Button android:text="−"
android:textColor="@color/operator" />
</TableRow>
<!-- Row 4: 0(span=2) . + -->
<TableRow>
<Button
android:text="0"
android:layout_span="2" /> <!-- spans cols 0+1 -->
<Button android:text="." />
<Button android:text="+"
android:textColor="@color/operator" />
</TableRow>
</TableLayout>
Preview
1,234
layout_span="4"
7
8
9
÷
4
5
6
×
1
2
3
−
0
span=2
.
+
// Key Attributes
android:fillViewport
"true" | "false"
If true, stretches the child to fill the ScrollView even if content is short. Important for centering content.
android:scrollbars
"vertical" | "horizontal" | "none"
Controls scrollbar visibility. "none" hides the scrollbar indicator.
android:overScrollMode
"always" | "ifContentScrolls" | "never"
Controls the glow/bounce effect at scroll edges.
android:nestedScrollingEnabled
"true" | "false"
Enable when inside a CoordinatorLayout or CollapsingToolbarLayout.
// Examples
A settings screen with many options needs to scroll. Wrap a LinearLayout (the only allowed child) inside a ScrollView. The LinearLayout holds all the settings rows. When the content is taller than the screen, the user can scroll vertically.
fragment_settings.xml
<!-- ScrollView: one direct child only -->
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true">
<!-- Single child: LinearLayout -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
<!-- Section Header -->
<TextView
android:text="Account"
android:textColor="@color/primary"
android:textSize="12sp"
android:layout_marginBottom="4dp" />
<!-- Setting item 1 -->
<LinearLayout android:orientation="horizontal">
<ImageView android:src="@drawable/ic_profile"/>
<TextView android:text="Edit Profile" android:layout_weight="1"/>
<ImageView android:src="@drawable/ic_chevron"/>
</LinearLayout>
<!-- ...more items... -->
<!-- Section Header -->
<TextView android:text="Notifications" />
<!-- Switch row -->
<LinearLayout android:orientation="horizontal">
<TextView
android:text="Push Notifications"
android:layout_weight="1" />
<Switch android:checked="true" />
</LinearLayout>
</LinearLayout>
</ScrollView>
Preview (scrollable ↕)
Never put a RecyclerView inside a ScrollView — they conflict. Use RecyclerView directly or nested scroll techniques.
// Key Attributes
android:columnCount
2, 3, 4, ... (integer)
Number of columns. Children wrap to next row after this count.
android:layout_columnSpan
2, 3, ... (integer)
On a child: span this many columns. Equivalent to table's colspan.
android:layout_rowSpan
2, 3, ... (integer)
On a child: span this many rows. Only possible in GridLayout (not TableLayout!).
android:layout_column
0, 1, 2, ... (integer)
Force a child to start at a specific column index.
android:layout_gravity
fill | fill_horizontal | center | start
How the child fills its cell. "fill" makes it expand to full cell size.
android:useDefaultMargins
"true" | "false"
Auto-applies default margins between cells when true.
// Examples
A dashboard where some cards are larger than others. The "Steps" card spans 2 columns for emphasis, and the "Heart Rate" card spans 2 rows to be taller. This column+row spanning is unique to GridLayout and cannot be done in TableLayout.
fragment_dashboard.xml
<GridLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:columnCount="2"
android:rowCount="3"
android:padding="8dp">
<!-- Steps: spans 2 columns (full width) -->
<TextView
android:layout_width="0dp"
android:layout_height="80dp"
android:layout_columnSpan="2"
android:layout_gravity="fill"
android:layout_margin="4dp"
android:text="🚶 Steps: 8,432"
android:background="@drawable/card_bg" />
<!-- Heart Rate: spans 2 rows (tall) -->
<TextView
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_rowSpan="2"
android:layout_gravity="fill"
android:layout_margin="4dp"
android:text="❤️ HR\n72 bpm"
android:background="@drawable/card_bg" />
<!-- Calories: 1×1 -->
<TextView
android:layout_width="0dp"
android:layout_height="70dp"
android:layout_gravity="fill"
android:layout_margin="4dp"
android:text="🔥 420 kcal"
android:background="@drawable/card_bg" />
<!-- Sleep: 1×1 -->
<TextView
android:layout_width="0dp"
android:layout_height="70dp"
android:layout_gravity="fill"
android:layout_margin="4dp"
android:text="😴 7h 20m"
android:background="@drawable/card_bg" />
</GridLayout>
Preview — Column + Row Spanning
layout_columnSpan="2"
🚶 Steps Today
8,432
rowSpan="2"
❤️
Heart Rate
72
bpm
🔥
Calories
420
😴
Sleep
7h 20m
GridLayout is the only built-in layout that supports both
rowSpan and columnSpan simultaneously.
📋 When to Use Which Layout — Quick Reference
| Layout | Nesting | Overlap | Row+Col Span | Performance | Best Use Case |
|---|---|---|---|---|---|
| LinearLayout | ★★☆ Can nest but avoid deep | ✗ | ✗ | Fast (flat) | Simple forms, stacked/side-by-side groups |
| RelativeLayout | ★★★ Flat by design | ✓ Limited | ✗ | Good | Rule-based positioning, older projects |
| ConstraintLayout | ★★★ Flattest hierarchy | ✓ | ✗ | Best (recommended) | Complex screens, all modern apps |
| FrameLayout | ★☆☆ Single child ideal | ✓ Z-stack | ✗ | Fast | Overlays, fragment containers, badges |
| TableLayout | ★★☆ Rows of cells | ✗ | Col only | Medium | Forms, data grids, calculators |
| ScrollView | ★☆☆ Wrapper only | ✗ | ✗ | OK for small lists | Long forms, articles, settings |
| GridLayout | ★★☆ Grid of cells | ✗ | ✓ Row + Col | Medium | Dashboards, galleries, app launchers |
Comments
Post a Comment