SwiftUI provides several powerful mechanisms for layout control and view coordination. Let’s explore some key concepts:

matchedGeometryEffect

matchedGeometryEffect allows you to create smooth animations between views that share the same identity. This is particularly useful for transitions where you want elements to morph from one state to another.

In the example below, we create a highlight effect that follows selected buttons:

struct MatchedGeometryView: View {
	@Namespace var namespace
	let groupID = "highlight"
	var body: some View {
		VStack {
			Button("Sign Up") {}
				.matchedGeometryEffect(id: groupID, in: namespace)
			Button("Log In") {}
				//.matchedGeometryEffect(id: groupID, in: namespace)
		}
		.overlay {
			Ellipse()
				.strokeBorder(Color.red, lineWidth: 1)
				.padding(-5)
				.matchedGeometryEffect(id: groupID, in: namespace, isSource: false)
		}
	}
}

#Preview("MatchedGeometryView") {
	MatchedGeometryView()
}

struct CoordinateSpaceView: View {
	var body: some View {
		VStack {
			Text("Hello")
			Text("Second")
				.overlay { GeometryReader { proxy in
					let _ = print([
						proxy.frame(in: .global),
						proxy.frame(in: .local),
						proxy.frame(in: .named("Stack"))
					])
					Color.clear
				}}
				.scaleEffect(0.5)
		}
		.coordinateSpace(name: "Stack")
	}
}

#Preview("CoordinateSpaceView") {
	CoordinateSpaceView()
}

Coordinate Spaces

SwiftUI offers different coordinate spaces for positioning and measuring views:

  • .global: Coordinates relative to the device screen
  • .local: Coordinates relative to the view’s immediate parent
  • .named: Custom coordinate space you define

The example above demonstrates how to access frame information in different coordinate spaces using GeometryReader.

struct DecorationView: View {
	var input: [String] = ["Dallas","San Francisco"]
	@State var maxWidth: CGFloat = 50
	var body: some View {
		VStack {
			ForEach(input, id: \.self) { item in
				Text(item)
					.overlay {
						GeometryReader { proxy in
							Color.clear
								.preference(key: MaxWidthKey.self, value: proxy.size.width)
						}
					}
			}
			Rectangle()
				.frame(width: maxWidth, height: 5)
				.padding()
			
		}
		.onPreferenceChange(MaxWidthKey.self) { value in
			maxWidth = value
		}
	}
}

struct MaxWidthKey: PreferenceKey {
	static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
		value = max(value, nextValue())
	}
	
	static var defaultValue: CGFloat = 0
}

#Preview("Preference-DecorationView") {
	DecorationView()
}

## Preferences and PreferenceKey

Preferences provide a way for child views to pass data up the view hierarchy to parent views. This is useful for:
- Collecting information from child views
- Coordinating layouts
- Sharing data between non-adjacent views

The `DecorationView` example shows how to:
1. Define a PreferenceKey for tracking maximum width
2. Use GeometryReader to measure view dimensions
3. Propagate values up the view hierarchy
4. React to preference changes with onPreferenceChange

struct CollectView: View {
	@State var superTitle: String = "None"
	var body: some View {
		VStack {
			Text("\(superTitle)")
				.font(.headline)
			List {
				ChildView()
				ChildView()
				ChildView()
			}
		}
		.onPreferenceChange(titleKey.self) { value in
			superTitle = "\(value)"
		}
	}
}

struct ChildView: View {
	@State var value: Int = 0
	var body: some View {
		Text("\(value)")
			.onAppear {
				value = (Int.random(in: 1000...5000))
			}
			.preference(key: titleKey.self, value: value)
		}
}

struct titleKey: PreferenceKey {
	static var defaultValue: Int = 0
	
	static func reduce(value: inout Int, nextValue: () -> Int) {
		let _ = print(nextValue())
		value = value + nextValue()
	}
}

#Preview("Preference-CollectView") {
	CollectView()
}

## Value Collection with Preferences

The `CollectView` demonstrates how to:
- Collect and aggregate values from multiple child views
- Use PreferenceKey's reduce function to combine values
- Update parent view state based on collected values

struct InteractionUI: View {
	var body: some View {
		HStack(alignment: .firstTextBaseline) {
			image
			Text("Pencil")
				.badge {
					Text("100")
				}
		}
	}
	
	var image: some View {
		Image(systemName: "pencil.circle.fill")
			.alignmentGuide(.firstTextBaseline) { dimension in
				dimension[VerticalAlignment.center]
			}
	}
}

#Preview {
    InteractionUI()
}

## Custom Alignment Guides

AlignmentGuide allows you to customize how views align relative to each other. You can:
- Define custom alignment behavior
- Override default alignment positions
- Create complex layouts with precise control

The `InteractionUI` example shows:
- Custom baseline alignment for images with text
- Badge positioning using alignment guides
- Creating reusable view modifiers with alignment customization

extension View {
	func badge<Badge: View>(@ViewBuilder content: () -> Badge) -> some View {
		self.overlay(alignment: .topTrailing) {
			content()
				.alignmentGuide(.top, computeValue: { dim in
					dim.height/2
				})
				.alignmentGuide(.trailing, computeValue: { dim in
					dim.width/2
				})
				.padding(3)
				.background {
					RoundedRectangle(cornerRadius: 5).fill(.teal)
				}
				.fixedSize()
		}
	}
}