This content originally appeared on DEV Community and was authored by Sebastien Lato
Parallax and scroll-reactive interfaces are everywhere in modern iOS design.
You see them in:
- Apple Music
- TV app
- App Store
- Photos
- Stocks
- Safari
These effects give depth, motion, and personality to your UI — and with SwiftUI’s modern APIs, they’re easy to build without hacks.
In this tutorial, we’ll build three clean, modern parallax effects using only pure SwiftUI.
🎯 What We’ll Build
Hero Image Parallax
Background image moves slower than foreground as you scroll.Fade + Scale Header
Perfect for content-heavy pages.Stretchy Pull-Down Header
Classic iOS pattern that feels light and natural.
All using GeometryReader, scroll offsets, and lightweight animations.
🧠 Key Technique: Scroll Offset Reading
We'll track scroll position using this simple helper:
struct OffsetKey: PreferenceKey {
static var defaultValue: CGFloat = 0
static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
value = nextValue()
}
}
Then we attach:
GeometryReader { geo in
Color.clear
.preference(key: OffsetKey.self,
value: geo.frame(in: .named("scroll")).minY)
}
.frame(height: 0)
This gives us a live scroll value.
🖼 1) Hero Image Parallax
struct ParallaxHeader: View {
let height: CGFloat
@Binding var offset: CGFloat
var body: some View {
let parallax = offset > 0 ? offset : offset / 4
Image("hero")
.resizable()
.scaledToFill()
.frame(height: height + (offset > 0 ? offset : 0))
.offset(y: parallax)
.clipped()
}
}
Use inside a ScrollView:
struct ParallaxDemo: View {
@State private var offset: CGFloat = 0
var body: some View {
ScrollView {
OffsetReader(offset: $offset)
ParallaxHeader(height: 300, offset: $offset)
content
}
.coordinateSpace(name: "scroll")
}
}
This creates a deep, smooth parallax effect similar to Apple TV or Music.
🌫 2) Fade + Scale Header (Dynamic Title)
struct FadingHeader: View {
@Binding var offset: CGFloat
var body: some View {
let progress = max(0, min(1, 1 - (offset / 120)))
Text("Dashboard")
.font(.largeTitle.bold())
.scaleEffect(0.8 + (0.2 * progress))
.opacity(progress)
}
}
Combine it with your scroll value:
.overlay(alignment: .topLeading) {
FadingHeader(offset: $offset)
.padding(.top, 40)
.padding(.leading, 20)
}
This matches the feel of many native system screens.
🫧 3) Stretchy Pull-Down Header
struct StretchyHeader: View {
let height: CGFloat
@Binding var offset: CGFloat
var body: some View {
Image("cover")
.resizable()
.scaledToFill()
.frame(height: height + max(offset, 0))
.offset(y: -max(offset, 0))
.clipped()
}
}
This creates the same stretchy behavior used in:
- Photos
- App Store product pages
- Safari reader mode
✔️ Final Result
You now have:
- parallax hero images
- fading/scaling titles
- stretchy pull-down headers
All powered by a clean scroll-offset technique and pure SwiftUI.
These effects instantly make your screens feel more alive, expressive, and modern — without adding complexity.
This content originally appeared on DEV Community and was authored by Sebastien Lato
Sebastien Lato | Sciencx (2025-11-25T23:49:50+00:00) How to Build Modern Parallax & Scroll Effects in SwiftUI. Retrieved from https://www.scien.cx/2025/11/25/how-to-build-modern-parallax-scroll-effects-in-swiftui/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.