I currently have a LazyVGrid
setup as such:
struct NetworkGrid: View {
var networks: [Network]
let columns = [
GridItem(.flexible()),
GridItem(.flexible()),
GridItem(.flexible()),
GridItem(.flexible())
]
var body: some View {
ScrollView {
LazyVGrid(columns: columns) {
ForEach(networks) { network in
NetworkCard(network: network)
}
}
}
}
}
I would like to set the number of grid columns based on the current window size, i.e.
func windowDidResize(_ notification: Notification) {
itemWidth = CGFloat(300)
if window.width <= itemWidth {
GridItem(.flexible()), GridItem(.flexible())
} else if window.width <= itemWidth * 2 {
GridItem(.flexible()), GridItem(.flexible()), GridItem(.flexible())
} else if window.width <= itemWidth * 3 {
GridItem(.flexible()), GridItem(.flexible()), GridItem(.flexible()), GridItem(.flexible())
}
...
}
How would I go about implementing such an observer with SwiftUI?
You can use onGeometryChange(for:of:action:) with Xcode 16.0+ targeting iOS 16.0+ or macOS 13.0+:
struct MyView: View {
@State private var size: CGSize = .zero
var body: some View {
ZStack {
Text("Hello World")
}
.onGeometryChange(for: CGSize.self) { proxy in
proxy.size
} action: { newSize in
size = newSize
}
}
}
If you want to update @State
or @ObservedObject
variables when the view is resized, you can use onAppear(perform:) to update the variables with the initial view size and onChange(of:perform:) to detect view size changes:
struct MyView: View {
@State private var size: CGSize = .zero
var body: some View {
GeometryReader { geometry in
ZStack {
Text("Hello World")
}.onAppear {
size = geometry.size
}.onChange(of: geometry.size) { newSize in
size = newSize
}
}
}
}
The SwiftUI equivalent of listening for window size would probably be using a GeometryReader
. In your example, you can read the size and dynamically decide the columns based on its width reading:
struct NetworkGrid: View {
var networks: [Network]
func columnsForWidth(width: CGFloat) -> [GridItem] {
print("Columns for width: \(width)")
return Array(repeating: GridItem(.flexible()), count: Int(width) / 100)
}
var body: some View {
GeometryReader { geometry in
ScrollView {
LazyVGrid(columns: columnsForWidth(width: geometry.size.width)) {
ForEach(networks) { network in
NetworkCard(network: network)
}
}
}
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With