| < How to add extra padding to the safe area | How to adjust the size of a view relative to its container > |
Updated for Xcode 16.4
New in iOS 17
SwiftUI’s visualEffect() modifier lets us read the geometry proxy for a view without using a GeometryReader, which means we can look at the size and location of a view without affecting its layout behavior.
Important: This modifier is specifically for applying visual effects such as adjusting colors or adding blur, and cannot adjust how the frame of your content is calculated for layout purposes. It can adjust frame-like things such as the offset and scale of your view, because they don’t affect layout.
As an example, the following code blurs each view in a scroll view by some blur amount that’s calculated by how far away the view is away from the center of its scroll view. That means views near the vertical center have little or no blur, whereas views on the outside are heavily blurred:
struct ContentView: View {
var body: some View {
ScrollView {
ForEach(0..<100) { i in
Text("Row \(i)")
.font(.largeTitle)
.frame(maxWidth: .infinity)
.visualEffect { content, proxy in
content.blur(radius: blurAmount(for: proxy))
}
}
}
}
func blurAmount(for proxy: GeometryProxy) -> Double {
let scrollViewHeight = proxy.bounds(of: .scrollView)?.height ?? 100
let ourCenter = proxy.frame(in: .scrollView).midY
let distanceFromCenter = abs(scrollViewHeight / 2 - ourCenter)
return Double(distanceFromCenter) / 100
}
}
Download this as an Xcode project

Tip: Calling proxy.frame(in: .scrollView) finds the size of this view in the innermost scroll view that contains it.
These visual effects work with any kind of position, including that generated through animation. For example, this makes a series of circles in a grid spin around, with each one dynamically recoloring based on a hue rotation:
struct ContentView: View {
@State private var rotationAmount = 0.0
var body: some View {
Grid {
ForEach(0..<3) { _ in
GridRow {
ForEach(0..<3) { _ in
Circle()
.fill(.green)
.frame(width: 100, height: 100)
.visualEffect { content, proxy in
content.hueRotation(.degrees(proxy.frame(in: .global).midY / 2))
}
}
}
}
}
.rotationEffect(.degrees(rotationAmount))
.onAppear {
withAnimation(.linear(duration: 5).repeatForever(autoreverses: false)) {
rotationAmount = 360
}
}
}
}
Download this as an Xcode project

The modifier’s name, visualEffect(), should make it clear that any adjustments you make are limited how the finished view looks – if you find yourself wanting to use it to adjust view content, you’re looking in the wrong place.
SAVE 50% All our books and bundles are half price for Black Friday, so you can take your Swift knowledge further for less! Get my all-new book Everything but the Code to make more money with apps, get the Swift Power Pack to build your iOS career faster, get the Swift Platform Pack to builds apps for macOS, watchOS, and beyond, or get the Swift Plus Pack to learn Swift Testing, design patterns, and more.