GeometryReader in SwiftUI
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
- Audio Descriptions • 11 minutes reading time.
- Creating macOS Menu Bar App in SwiftUI • 4 minutes reading time.
- How to Position Views in SwiftUI • 1 minutes reading time.
Share
Share Bluesky Mastodon Twitter LinkedIn Facebook