GeometryReader is a SwiftUI view that provides access to the size and position of its parent container. It's essential for creating responsive layouts, custom alignments, and size-dependent views.

What is GeometryReader?

GeometryReader is a container view that makes its child view aware of its size and coordinate space. It passes a GeometryProxy to its content closure, which you can use to query dimensional information.

Basic Usage

Here's a simple example of using GeometryReader:

import SwiftUI

struct GeometryExample: View {
    var body: some View {
        GeometryReader { geometry in
            VStack {
                Text("Width: \(geometry.size.width)")
                Text("Height: \(geometry.size.height)")
            }
            .frame(width: geometry.size.width, height: geometry.size.height)
            .background(Color.blue.opacity(0.3))
        }
    }
}

Creating Responsive Layouts

Use GeometryReader to create layouts that adapt to available space:

struct ResponsiveGrid: View {
    var body: some View {
        GeometryReader { geometry in
            let columns = Int(geometry.size.width / 100)
            let spacing: CGFloat = 10
            let itemWidth = (geometry.size.width - (CGFloat(columns + 1) * spacing)) / CGFloat(columns)

            ScrollView {
                LazyVGrid(
                    columns: Array(repeating: GridItem(.fixed(itemWidth), spacing: spacing), count: columns),
                    spacing: spacing
                ) {
                    ForEach(1...50, id: \.self) { item in
                        RoundedRectangle(cornerRadius: 8)
                            .fill(Color.blue)
                            .frame(height: itemWidth)
                            .overlay(Text("\(item)"))
                    }
                }
                .padding(spacing)
            }
        }
    }
}

Coordinate Spaces

GeometryReader can convert coordinates between different coordinate spaces:

struct CoordinateExample: View {
    var body: some View {
        GeometryReader { geometry in
            ScrollView {
                ForEach(0..<20) { index in
                    GeometryReader { itemGeometry in
                        let minY = itemGeometry.frame(in: .global).minY
                        let screenHeight = geometry.size.height
                        let progress = (screenHeight - minY) / screenHeight

                        Text("Item \(index)")
                            .frame(height: 100)
                            .frame(maxWidth: .infinity)
                            .background(
                                Color.blue.opacity(Double(progress))
                            )
                    }
                    .frame(height: 100)
                }
            }
        }
    }
}

Creating Circular Progress View

Here's a practical example using GeometryReader:

struct CircularProgressView: View {
    let progress: Double

    var body: some View {
        GeometryReader { geometry in
            ZStack {
                Circle()
                    .stroke(Color.gray.opacity(0.3), lineWidth: 20)

                Circle()
                    .trim(from: 0, to: progress)
                    .stroke(Color.blue, style: StrokeStyle(lineWidth: 20, lineCap: .round))
                    .rotationEffect(.degrees(-90))

                Text("\(Int(progress * 100))%")
                    .font(.system(size: geometry.size.width * 0.3, weight: .bold))
            }
        }
        .aspectRatio(1, contentMode: .fit)
    }
}

Caveats

  • GeometryReader takes all available space by default

  • Can cause layout issues if not properly constrained

  • Overusing GeometryReader can impact performance

  • Consider using layout protocols (iOS 16+) for some use cases

Wrap up

GeometryReader is a powerful tool for creating responsive and adaptive layouts in SwiftUI. While it should be used judiciously, it's essential for scenarios where you need to know the size and position of views.

Resources:

Read more

Share


Share Bluesky Mastodon Twitter LinkedIn Facebook