Reputation: 16986
I'm creating a form with multiple sections in SwiftUI. Each section contains several text fields, each with a label.
I'd like to align the leading edges of the text fields with each other and also with the center of the view.
I'm able to align the leading edges of the text fields within a section using the following:
extension HorizontalAlignment {
private struct LeadingEdgeAlignment: AlignmentID {
/// A custom alignment for leading edges.
static func defaultValue(in context: ViewDimensions) -> CGFloat {
context[.leading]
}
}
/// A guide for aligning leading edges.
static let leadingEdge = HorizontalAlignment(LeadingEdgeAlignment.self)
}
struct ContentView: View {
var body: some View {
Form {
Section(header: Text("Section One")) {
VStack(alignment: .leadingEdge) {
HStack {
Text("Primary")
TextField("", text: .constant(""))
.frame(minWidth: nil, idealWidth: nil, maxWidth: 75, minHeight: nil, maxHeight: nil)
.alignmentGuide(.leadingEdge) { $0[HorizontalAlignment.leading] }
.textFieldStyle(RoundedBorderTextFieldStyle())
}
HStack {
Text("Secondary")
TextField("", text: .constant(""))
.frame(minWidth: nil, idealWidth: nil, maxWidth: 75, minHeight: nil, maxHeight: nil)
.alignmentGuide(.leadingEdge) { $0[HorizontalAlignment.leading] }
.textFieldStyle(RoundedBorderTextFieldStyle())
}
}
}
Section(header: Text("Section Two")) {
VStack(alignment: .leadingEdge) {
HStack {
Text("Milk")
TextField("", text: .constant(""))
.frame(minWidth: nil, idealWidth: nil, maxWidth: 75, minHeight: nil, maxHeight: nil)
.alignmentGuide(.leadingEdge) { $0[HorizontalAlignment.leading] }
.textFieldStyle(RoundedBorderTextFieldStyle())
}
HStack {
Text("Cheesecake")
TextField("", text: .constant(""))
.frame(minWidth: nil, idealWidth: nil, maxWidth: 75, minHeight: nil, maxHeight: nil)
.alignmentGuide(.leadingEdge) { $0[HorizontalAlignment.leading] }
.textFieldStyle(RoundedBorderTextFieldStyle())
}
}
}
}
}
}
However, so far all my attempts to create alignment guides that span sections have failed.
How does one align views across form sections?
Upvotes: 3
Views: 481
Reputation: 16986
Based on the answer from lorem ipsum
I was able to achieve what I wanted using LazyVGrid
.
struct ContentView: View {
let columns = [GridItem(.flexible(), alignment: .trailing), GridItem(.flexible(), alignment: .leading)]
var body: some View {
Form {
Section(header: Text("Section One")) {
LazyVGrid(columns: columns) {
Text("Primary")
TextField("", text: .constant(""))
.frame(minWidth: nil, idealWidth: nil, maxWidth: 75, minHeight: nil, maxHeight: nil)
.textFieldStyle(RoundedBorderTextFieldStyle())
Text("Secondary")
TextField("", text: .constant(""))
.frame(minWidth: nil, idealWidth: nil, maxWidth: 75, minHeight: nil, maxHeight: nil)
.textFieldStyle(RoundedBorderTextFieldStyle())
}
}
Section(header: Text("Section Two")) {
LazyVGrid(columns: columns) {
Text("Milk")
TextField("", text: .constant(""))
.frame(minWidth: nil, idealWidth: nil, maxWidth: 75, minHeight: nil, maxHeight: nil)
.textFieldStyle(RoundedBorderTextFieldStyle())
Text("Cheesecake")
TextField("", text: .constant(""))
.frame(minWidth: nil, idealWidth: nil, maxWidth: 75, minHeight: nil, maxHeight: nil)
.textFieldStyle(RoundedBorderTextFieldStyle())
}
}
}
}
}
Upvotes: 0
Reputation: 29676
Since you are splitting in half one way to do it is to have even columns. But you have to handle the significant difference in text length
struct AlignedSectionView: View {
let columns = [GridItem(), GridItem()]
var body: some View {
Form {
Section(header: Text("Section One")) {
//Divide the section in half
LazyVGrid(columns: columns, alignment: .leadingEdge) {
HStack {
Text("Primary")
//Push the TextField to the Halfway point
Spacer()
TextField("", text: .constant(""))
.frame(minWidth: nil, idealWidth: nil, maxWidth: 75, minHeight: nil, maxHeight: nil)
.alignmentGuide(.leadingEdge) { $0[HorizontalAlignment.leading] }
.textFieldStyle(RoundedBorderTextFieldStyle())
}
//Fill in the column
Spacer()
HStack {
Text("Secondary")
Spacer()
TextField("", text: .constant(""))
.frame(minWidth: nil, idealWidth: nil, maxWidth: 75, minHeight: nil, maxHeight: nil)
.alignmentGuide(.leadingEdge) { $0[HorizontalAlignment.leading] }
.textFieldStyle(RoundedBorderTextFieldStyle())
}
}
}
Section(header: Text("Section Two")) {
//Divide the section in half
LazyVGrid(columns: columns, alignment: .leadingEdge) {
HStack {
Text("Milk")
//Push the TextField to the Halfway point
Spacer()
TextField("", text: .constant(""))
.frame(minWidth: nil, idealWidth: nil, maxWidth: 75, minHeight: nil, maxHeight: nil)
.alignmentGuide(.leadingEdge) { $0[HorizontalAlignment.leading] }
.textFieldStyle(RoundedBorderTextFieldStyle())
}
//Fill in the column
Spacer()
HStack {
Text("Cheesecake")
//So it doesnt go to the next line
.lineLimit(1)
Spacer()
TextField("", text: .constant(""))
.frame(minWidth: nil, idealWidth: nil, maxWidth: 75, minHeight: nil, maxHeight: nil)
.alignmentGuide(.leadingEdge) { $0[HorizontalAlignment.leading] }
.textFieldStyle(RoundedBorderTextFieldStyle())
}
}
}
}
//One way of dealing with the difference in text sizes is to allow the text to get smaller to fit
.minimumScaleFactor(0.9)
}
}
Upvotes: 2