This is probably a basic question but I’m really struggling reliably aligning simple groups of items in Swift UI and have not found a simple solution.
I have a number of screens in an app I’m working on which combine a text string and a button but I am struggling to align these without using many VStacks within VStacks. My understanding of Swift UI was that this should not be necessary for simple visual structures - and that overcomplicating the visual layout could potentially cause issues further down the lines.
I have used the lazyGrid view with a 2 column structure, wrapped in a VStack which is aligned. I have tried a few combinations of aligning the elements to the leading edge but I am still seeing them apparently aligning to the centre.
Could someone please advise.
import SwiftUI
struct ContentView: View {
let column = [
GridItem(.fixed(200))
]
let columns = [
GridItem(.fixed(200)),
GridItem(.flexible(minimum: 50, maximum: .infinity))
]
var body: some View {
VStack(alignment: .leading) {
// ################################################################################
// Lazy Grid - no HStack
// ################################################################################
VStack {
Text("Secondary Items").fontWeight(.bold)
LazyVGrid(columns: columns, spacing: 20) {
Text("Clear Files")
Button(action: {
}) {
HStack(spacing: 10) {
Text("Clear")
}
}
}
.background(Color.green.opacity(0.0))
// .border(Color.red)
LazyVGrid(columns: columns, spacing: 20) {
Text("Clear Scripts")
Button(action: {
}) {
HStack(spacing: 10) {
Text("Clear")
}
}
}
.background(Color.green.opacity(0.0))
// .border(Color.red)
LazyVGrid(columns: columns, spacing: 20) {
Text("Delete General")
Button(action: {
print("Check processingComplete")
}) {
HStack(spacing: 10) {
Text("Delete")
}
}
}
.background(Color.green.opacity(0.0))
// .border(Color.red)
LazyVGrid(columns: columns, spacing: 20) {
Text("Clear Root")
Button(action: {
}) {
HStack(spacing: 10) {
Text("Clear")
}
}
}
.background(Color.green.opacity(0.0))
// .border(Color.red)
LazyVGrid(columns: columns, spacing: 20) {
Text("Clear Encryption")
Button(action: {
}) {
HStack(spacing: 10) {
Text("Clear")
}
}
}
.background(Color.green.opacity(0.0))
// .border(Color.red)
}
.frame(width: 400, alignment: .leading)
.padding()
}
.padding()
Spacer()
}
}
You are indeed overcomplicating this. LazyVGrid
is a "grid". You only need one of these to display a grid of views. You do not need one LazyVGrid
for each row.
You should put all the Text
-Button
pairs into one LazyVGrid
. The alignment of each column can be specified as part of the GridItem
.
let columns = [
GridItem(.fixed(200), alignment: .leading), // <------ HERE!
GridItem(.flexible(minimum: 50, maximum: .infinity))
]
var body: some View {
VStack {
Text("Secondary Items").fontWeight(.bold)
LazyVGrid(columns: columns, spacing: 20) {
Text("Clear Files")
Button("Clear") {}
Text("Clear Scripts")
Button("Clear") {}
Text("Delete General")
Button("Delete") {}
Text("Clear Root")
Button("Clear") {}
Text("Clear Encryption")
Button("Clear") {}
}
}
.frame(width: 400, alignment: .leading)
.padding()
}
Since the grid is not scrollable, LazyVGrid
isn't actually lazy. I'd suggest using a regular Grid
instead.
var body: some View {
Grid(horizontalSpacing: 160) {
GridRow {
Text("Secondary Items").fontWeight(.bold)
.gridCellColumns(2)
}
GridRow {
Text("Clear Files")
.gridCellAnchor(.leading)
Button("Clear") {}
}
GridRow {
Text("Clear Scripts")
.gridCellAnchor(.leading)
Button("Clear") {}
}
GridRow {
Text("Delete General")
.gridCellAnchor(.leading)
Button("Delete") {}
}
GridRow {
Text("Clear Root")
.gridCellAnchor(.leading)
Button("Clear") {}
}
GridRow {
Text("Clear Encryption")
.gridCellAnchor(.leading)
Button("Clear") {}
}
}
.padding()
}
The alignment of the views can be set using gridCellAnchor
. If you want the buttons to be leading-aligned as well, you can pass the alignment to Grid.init
:
Grid(alignment: .leading, horizontalSpacing: 160) {
// ^^^^^^^^^^^^^^^^^^^
GridRow {
Text("Secondary Items").fontWeight(.bold)
.gridCellColumns(2)
.gridCellAnchor(.center) // now this needs to be centered
}
GridRow {
Text("Clear Files") // don't need .gridCellAnchor here
Button("Clear") {}
}
// and so on...
}