Skip to content
Prepare to Grow

SwiftUI Fundamentals

Layout with Stacks, Frames, and Spacing

Reason about SwiftUI's proposal-based layout system and build adaptive interfaces with stacks, grids, frames, and safe areas.

Intermediate6 min read2 guided activities

Before you begin

What you will understand

  • Describe the parent-proposal and child-size layout process.
  • Choose appropriate stack and grid containers.
  • Use frames, alignment, spacing, and priorities deliberately.
  • Create layouts that adapt to text size and available width.
01

Learning stage

Concept Explanation

SwiftUI layout is a negotiation. A parent proposes a size to each child, the child chooses a size that fits its own rules, and the parent positions the returned sizes. A frame does not usually force a child to redraw at an arbitrary size; it participates in that negotiation and can wrap the child with minimum, ideal, or maximum constraints.

HStack, VStack, and ZStack arrange views horizontally, vertically, and in depth. Lazy stacks and grids delay creation for large scrolling content. Alignment guides coordinate meaningful edges, while Spacer consumes flexible space. Prefer flexible relationships over fixed screen dimensions.

Adaptive layout must survive small devices, split views, localization, and larger accessibility text. Let text wrap, use layoutPriority only when content importance justifies it, and choose alternatives such as ViewThatFits when genuinely different arrangements are needed.

  • Proposal: the size a parent offers a child.
  • Response: the size a child chooses for that proposal.
  • Stack: arranges children along an axis or depth.
  • Frame: adds sizing constraints and alignment around a view.
  • Safe area: system-defined region that avoids obstructed content.
02

Learning stage

Syntax & Examples

The card uses flexible width and semantic alignment without depending on one device size.

ProgressCard.swiftswift
import SwiftUI

struct ProgressCard: View {
  let title: String
  let completed: Int
  let total: Int

  var body: some View {
    HStack(alignment: .firstTextBaseline, spacing: 16) {
      VStack(alignment: .leading, spacing: 6) {
        Text(title)
          .font(.headline)
          .fixedSize(horizontal: false, vertical: true)
        Text("Keep learning at your pace")
          .font(.subheadline)
          .foregroundStyle(.secondary)
      }
      .frame(maxWidth: .infinity, alignment: .leading)

      Text("(completed)/(total)")
        .font(.title3.monospacedDigit().bold())
        .accessibilityLabel("(completed) of (total) complete")
    }
    .padding()
    .background(.thinMaterial, in: .rect(cornerRadius: 18))
  }
}
The leading column accepts remaining width, text can grow vertically, and baseline alignment keeps the progress value visually related to the title.
03

Learning stage

Real-World Usage

Connect the SwiftUI concept to complete, maintainable application features.

  • Build cards that work on iPhone, iPad, and split-screen widths.
  • Create responsive grids with adaptive GridItem values.
  • Respect safe areas while allowing selected backgrounds to extend beneath system regions.
  • Support Dynamic Type without clipped labels or overlapping controls.
04

Learning stage

Common Mistakes

Identify patterns that weaken ownership, identity, adaptation, accessibility, or user experience.

  • Using UIScreen bounds as the source of every view size.
  • Applying fixed width and height values to text-heavy content.
  • Adding Spacer repeatedly to compensate for an unclear container.
  • Using GeometryReader when normal stacks and frames already express the relationship.
  • Ignoring localization and accessibility text sizes during layout review.
05

Learning stage

Practice Exercises

Build the behavior in a small Xcode project and review it in multiple states.

Activity 1

Build an adaptive summary card

Create a card with a title, optional subtitle, progress value, and action. Test narrow width and an accessibility text size.

Hint: Avoid fixed heights and allow the text column to grow.

Activity 2

Create a flexible grid

Display feature tiles in a LazyVGrid that automatically changes column count based on available width.

Hint: Use an adaptive GridItem with a meaningful minimum width.

06

Learning stage

Knowledge Check

Answer each question before revealing the explanation.

QUESTION 1

What happens first in SwiftUI layout?

  1. A.A parent proposes a size to a child
  2. B.A child reads the physical screen
  3. C.Every view chooses the same size
  4. D.SwiftUI creates Auto Layout constraints
Reveal answer

A parent proposes a size to a child

The child then chooses a size under its rules and the parent positions it.

QUESTION 2

Why are fixed heights risky for text content?

Reveal answer

Text can require more space after localization or Dynamic Type changes, causing clipping or overlap.

Flexible vertical sizing lets content remain readable across user and device contexts.

07

Learning stage

Interview Preparation

Explain the design in terms of data flow, identity, lifecycle, platform behavior, and trade-offs.

How would you explain SwiftUI's layout system?

Short answer: Parents propose sizes, children choose fitting sizes, and parents position the results.

Explore the detailed answer

Each container participates in a proposal–response process. Modifiers such as frame wrap a view and adjust the proposals or reported size. This explains why a maxWidth frame, fixedSize, layoutPriority, and GeometryReader have different effects and why reading only the screen width is usually the wrong model.

Possible follow-ups

  • • When is GeometryReader appropriate?
  • • How would you test an adaptive layout?
08

Learning stage

Key Takeaways

SwiftUI layout is a cooperative negotiation, not a collection of absolute coordinates. Use semantic containers, flexible constraints, and representative accessibility and localization tests.

  • Parents propose; children choose; parents position.
  • Stacks and grids express structural relationships.
  • Frames wrap views with constraints and alignment.
  • Avoid fixed dimensions for dynamic text.
  • Test multiple widths, languages, and text sizes.