NEW Tool! SwiftFairy: Local Swift and SwiftUI code reviews for your coding agent. Learn more ...NEW Tool! SwiftFairy:Local code reviews for your agents. Learn more...
← All SwiftFairy Scrolls

SwiftFairy Scroll

SwiftUI Layout & Resizability

Build interfaces that adapt to any window size, device, and text size by sizing views flexibly, structuring scrolling content correctly, and choosing the right SwiftUI layout API for each job.

What your agent can improve

Sizing and flexibility

Identify fixed frames, rigid text, and image sizing that break as content, language, or Dynamic Type changes, with guidance to help your agent keep views flexible.

Adaptive layout

Help your agent choose a layout from the space available rather than the device or orientation, so screens adapt to resizable windows, split views, and folding devices.

GeometryReader and measurement

Find GeometryReader used to size, divide, or track content, and give your agent the layout, scroll, and geometry APIs that replace each use.

Scrolling, bars, and safe areas

Give your agent guidance on where scroll views, toolbars, search, and backgrounds belong in the hierarchy, so content scrolls beneath bars and fills the safe area correctly.

Issues SwiftUI Layout & Resizability flags

SwiftUI Layout & Resizability flags over 110 issues in your code. Each finding arrives at the line where the issue occurs, with the guidance and code example written for that case.

  • GeometryReader used to size, divide, or position content
  • GeometryReader tracking scroll position or driving a visual effect
  • Fixed frames and fixedSize() that stop text wrapping
  • Images framed without resizable() or a scaling mode
  • Scroll views sharing a stack with bars, or wrapped in a ZStack
  • Eager stacks of repeated content, and lazy stacks across the scroll axis
  • Nested NavigationStacks, and sheets attached inside lazy content
  • Toolbar buttons without a title or symbol, and custom toolbar backgrounds
Alone SwiftFairy

Token efficiency

Your agent skips millions of tokens of reasoning and reads guidance only for the issues flagged.

Cross-file insight

Follows your view hierarchy across files and presentations, beyond single views and functions.

Deep knowledge

Built on our books and articles, and Natalia's work on Apple's SwiftUI team.

Example findings

These examples show the patterns SwiftFairy flags and the guidance your agent can use to address them. Highlighted lines mark the code to review; each finding indicates whether the guidance is a requirement, recommendation, or consideration.

Consider

Stretch a header with visualEffect instead of resizing it

A GeometryReader that resizes a header from its frame in the scroll view changes layout on every frame of the scroll. The header's size, the scroll view's content size, and the positions of the views beneath it are recalculated as the user pulls, although the stretch is only a drawing effect.

Pattern flagged for review

// In a ScrollView:
GeometryReader { proxy in
     let pull = max(
         0,
         proxy.frame(in: .scrollView).minY
     )
     HeaderImage()
         .frame(height: 280 + pull)
         .offset(y: -pull)
}
.frame(height: 280)

A possible improvement

// On HeaderImage, in a ScrollView:
.frame(height: 280)
.visualEffect { effect, proxy in
     let height = proxy.size.height
     let pull = max(
         0,
         proxy.frame(in: .scrollView).minY
     )
     return effect.scaleEffect(
         (height + pull) / height,
         anchor: .bottom
     )
}

Apply visualEffect to the header and scale it from the bottom anchor. The effect changes only how the header is drawn: it keeps one size in layout, so the scroll view's content size and the views beneath it stay where they are as the user scrolls.

Consider

Attach persistent content to a scroll view through the safe area

A stack that places a header or footer beside a scroll view along its scrolling axis shortens the viewport. Content then clips at that boundary instead of scrolling beneath the adjacent view.

Pattern flagged for review

VStack(spacing: 0) {
     ScrollView {
         LazyVStack {
             ForEach(items) { item in
                 ItemRow(item: item)
             }
         }
     }
     Text("Changes are saved automatically.")
         .padding()
         .frame(maxWidth: .infinity)
         .background(.bar)
}

A possible improvement

ScrollView {
     LazyVStack {
         ForEach(items) { item in
             ItemRow(item: item)
         }
     }
}
.safeAreaInset(edge: .bottom, spacing: 0) {
     Text("Changes are saved automatically.")
         .padding()
         .frame(maxWidth: .infinity)
         .background(.bar)
}

Attach the footer through a safe-area inset so the scroll view retains its extent and reserves space for that content. Intentionally bounded scrolling regions, such as inset cards or independent panes, can keep their stack.

…and over 100 other issues.

Put the findings to work

Ask your agent to review a code change or a complete codebase with SwiftFairy. Your agent uses the findings and their accompanying code examples to resolve issues in your code.

How to use SwiftFairy

Try SwiftUI Layout & Resizability free for one day

Activate your free trial within the app at any time.

Choose lifetime access, a fixed term, or a subscription for this Scroll, or get all four together in a bundle.

Explore the other Scrolls