How to use GeometryReader for containing one view in another in swiftUI?

By | February 3, 2025

There are different ways to limit or constrain a subview within its superview in SwiftUI. ‘GeometryReader’ is one among those for relative sizing of the subviews in a view. We will see different ways of using ‘GeometryReader’ in below examples.

  1. ContainerExample:
  • Uses basic containment with percentage-based sizing
  • Child view takes up 80% of parent’s width and height
  • Uses position to center the child view
import SwiftUI

struct ContentView: View {
    var body: some View {
        // Example 1: Basic containment
        VStack(spacing: 20) {
            ContainerExample()
        }
    }
}

// Example 1: Basic containment with fixed size
struct ContainerExample: View {
    var body: some View {
        GeometryReader { geometry in
            // Parent container
            RoundedRectangle(cornerRadius: 10)
                .fill(.blue.opacity(0.2))
                .overlay(
                    // Child view using parent's dimensions
                    RoundedRectangle(cornerRadius: 5)
                        .fill(.blue)
                        .frame(
                            width: geometry.size.width * 0.8,
                            height: geometry.size.height * 0.8
                        )
                        .position(
                            x: geometry.size.width / 2,
                            y: geometry.size.height / 2
                        )
                )
        }
        .frame(height: 200)
    }
}

#Preview {
    ContentView()
        .padding()
}

2. CenteredContentExample:

  • Shows how to center content with dynamic sizing
  • Uses min to ensure content doesn’t exceed container
  • Demonstrates padding consideration in calculations
import SwiftUI

struct ContentView: View {
    var body: some View {
        // Example 1: Basic containment
        VStack(spacing: 20) {
            CenteredContentExample()
        }
    }
}

// Example 2: Centered content with dynamic sizing
struct CenteredContentExample: View {
    var body: some View {
        GeometryReader { geometry in
            ZStack {
                // Background
                RoundedRectangle(cornerRadius: 10)
                    .fill(.green.opacity(0.2))
                
                // Centered content with padding
                VStack {
                    Text("Centered Content")
                        .font(.headline)
                    RoundedRectangle(cornerRadius: 5)
                        .fill(.green)
                        .frame(
                            width: min(geometry.size.width - 40, 300),
                            height: min(geometry.size.height - 40, 100)
                        )
                }
            }
        }
        .frame(height: 200)
    }
}

#Preview {
    ContentView()
        .padding()
}

3. ResponsiveContainerExample:

  • Shows how to create a responsive grid layout
  • Adapts to available space
  • Uses spacing and padding considerations
import SwiftUI

struct ContentView: View {
    var body: some View {
        // Example 1: Basic containment
        VStack(spacing: 20) {
            ResponsiveContainerExample()
        }
    }
}

// Example 3: Responsive container that adapts to content
struct ResponsiveContainerExample: View {
    var body: some View {
        GeometryReader { geometry in
            let availableWidth = geometry.size.width
            let availableHeight = geometry.size.height
            
            ZStack {
                // Background container
                RoundedRectangle(cornerRadius: 10)
                    .fill(.purple.opacity(0.2))
                
                // Dynamic content grid
                HStack(spacing: 10) {
                    ForEach(0..<3) { index in
                        RoundedRectangle(cornerRadius: 5)
                            .fill(.purple)
                            .frame(
                                width: (availableWidth - 40) / 3,
                                height: availableHeight * 0.6
                            )
                    }
                }
                .position(
                    x: availableWidth / 2,
                    y: availableHeight / 2
                )
            }
        }
        .frame(height: 200)
    }
}

#Preview {
    ContentView()
        .padding()
}

4. ProportionalContainerExample:

  • Maintains aspect ratio of the contained view
  • Uses aspectRatio with contentMode: .fit
  • Ensures square shape while staying within bounds
import SwiftUI

struct ContentView: View {
    var body: some View {
        // Example 1: Basic containment
        VStack(spacing: 20) {
            ProportionalContainerExample()
        }
    }
}

// Example 4: Proportional container with aspect ratio
struct ProportionalContainerExample: View {
    var body: some View {
        GeometryReader { geometry in
            // Parent container
            RoundedRectangle(cornerRadius: 10)
                .fill(.orange.opacity(0.2))
                .overlay(
                    // Child view maintaining aspect ratio
                    RoundedRectangle(cornerRadius: 5)
                        .fill(.orange)
                        .aspectRatio(1.0, contentMode: .fit)
                        .frame(
                            width: min(geometry.size.width, geometry.size.height) * 0.8
                        )
                        .position(
                            x: geometry.size.width / 2,
                            y: geometry.size.height / 2
                        )
                )
        }
        .frame(height: 200)
    }
}

#Preview {
    ContentView()
        .padding()
}
#Preview {
    ContentView()
        .padding()
}

Key tips for using GeometryReader:

a. Always account for padding in your calculations

b. Use position for precise positioning

c. Consider using min and max for boundaries

d. Remember that GeometryReader takes up all available space

e. Use local variables to make calculations clearer

Thanks for reading!

Leave a Reply

Your email address will not be published. Required fields are marked *