I'm currently developing an app that shows the code for different SwiftUI files in a single column. I'm using multiple WKWebView instances to display each file (for easy hosting + built-in syntax highlighting support). The WebViews are sized to fit the container with padding:
For some of the larger projects – with numerous files – I'm attempting to implement a LazyVGrid that would display the smaller, supporting files side-by-side as such:
However, I have been unable to get the grid to resize into a single-column when the window is made smaller (or even into a 3-column if the user is using a super-wide monitor; although, this is much less of a priority). Is a LazyVGrid the best way to go about this, or should I be taking a different approach? I feel like I'm so close.
GridLayout.swift
struct GridLayout: View {
let data: [String]
enum dataType { case title; case url }
let columns = [GridItem(.flexible()), GridItem(.flexible())]
func get(_ forType: dataType, _ string: String) -> String {
if forType == .title { return string.components(separatedBy: "*")[0] }
if forType == .url { return string.components(separatedBy: "*")[1] }
return ""
}
var body: some View {
VStack {
LazyVGrid(columns: columns) {
ForEach(data, id: \.self) { i in
CodeView(title: get(.title, i), height: 500, url: get(.url, i))
.frame(minWidth: 300, idealWidth: 400, maxWidth: .infinity, alignment: .center)
}
}
}
}
}
There are several ways to do this with a GeometryReader
. Here I’m using .flexible()
grid items but varying the number of columns based on the overall width of the parent view: if the width is under 800px, do 1 column; if the width is between 800 and 1200px, do 2 columns; otherwise do 3 columns.
var body: some View {
GeometryReader { geometry in
let gridItem = GridItem(.flexible())
var columnCount: Int = {
switch geometry.size.width {
case 0..<800:
return 1
case 800..<1200:
return 2
default:
return 3
}
}()
LazyVGrid(columns: Array(repeating: gridItem,
count: columnCount)) {
ForEach(1..<5) { _ in
Rectangle()
.fill(Color.gray)
.frame(height: 500)
}
}
}
}