swiftswiftuinsviewnswindownsnotifications

Observe window resize event with SwiftUI


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?


Solution

  • 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)
                        }
                    }
                }
            }
        }
    }