Skip to main content

How to dynamically adjust the appearance of a view based on its size and location

About 3 minSwiftSwiftUIArticle(s)bloghackingwithswift.comcrashcourseswiftswiftuixcodeappstore

How to dynamically adjust the appearance of a view based on its size and location 관련

SwiftUI by Example

Back to Home

How to dynamically adjust the appearance of a view based on its size and location | SwiftUI by Example

How to dynamically adjust the appearance of a view based on its size and location

Updated for Xcode 15

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 projectopen in new window

A scrolling list of rows, where rows near the center are sharp and rows near the edges are blurry.
A scrolling list of rows, where rows near the center are sharp and rows near the edges are blurry.

Tips

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 projectopen in new window

A 3x3 grid of rotating circles, where each circle changes colors as it moves.
A 3x3 grid of rotating circles, where each circle changes colors as it moves.

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.

Similar solutions…
How to adjust the size of a view relative to its container | SwiftUI by Example

How to adjust the size of a view relative to its container
How to automatically switch between HStack and VStack based on size class | SwiftUI by Example

How to automatically switch between HStack and VStack based on size class
How to dynamically adjust the color of an SF Symbol | SwiftUI by Example

How to dynamically adjust the color of an SF Symbol
How to adjust the position of a view using its offset | SwiftUI by Example

How to adjust the position of a view using its offset
How to create a document-based app using FileDocument and DocumentGroup | SwiftUI by Example

How to create a document-based app using FileDocument and DocumentGroup

이찬희 (MarkiiimarK)
Never Stop Learning.