I have the following code:
struct ContentView: View {
@State var isOn: Bool = false
var body: some View {
HStack(alignment: .top) {
Toggle(isOn: $isOn) {
Text("Hello")
}
Text("The quick brown fox jumped over the lazy dog")
Spacer()
Button("Go") {
print("Knock knock.")
}
.padding()
}
.padding()
}
}
Which results in:
How do I vertically align the top line: The quick brown fox
and Go
with desiredly positioned Hello
?
Of course I can manually tune the alignment with hard-coded .offset()
; I have this now in my code. But that's ugly and will fall apart if I'd change the font size(s) for example. I'm looking for a proper method without hard-code values.
Isn't this possible with SwiftUI alignment features?
Here is one approach (the Toggle button toggles background colors on/off):
import SwiftUI
struct ContentView: View {
@State var isOn: Bool = false
@State var c1: Color = Color(red: 1.00, green: 0.75, blue: 0.75)
@State var c2: Color = Color(red: 0.75, green: 1.00, blue: 0.75)
@State var c3: Color = Color(red: 1.00, green: 1.00, blue: 0.00)
@State var c4: Color = Color(red: 0.80, green: 1.00, blue: 0.75)
@State var c5: Color = Color(red: 0.75, green: 0.75, blue: 0.25)
var body: some View {
HStack(alignment: .top) {
Spacer()
Toggle(isOn: $isOn) {
Text("Hello")
.background(isOn ? c1 : .clear)
}
.background(isOn ? c2 : .clear)
.offset(CGSize(width: 0.0, height: -5.0))
Text("The quick brown fox jumped over the lazy dog")
.background(isOn ? c3 : .clear)
Spacer()
Button("Go") {
print("Knock knock.")
}
.background(isOn ? c4 : .clear)
Spacer()
}
.background(isOn ? c5 : .clear)
.padding()
}
}
Output (red line is added after, to show the text baselines):
You would probably want to use GeometryReader to calculate the correct offset, rather than using the hard-coded y: -5.0
Edit -- after quick searching for dynamic sizing instead of hard-coded y: -5.0
Based on info found here: https://stackoverflow.com/a/63050004/6257435
Looks like custom .alignmentGuide
is what you need:
import SwiftUI
extension VerticalAlignment {
private enum XAlignment : AlignmentID {
static func defaultValue(in d: ViewDimensions) -> CGFloat {
return d[VerticalAlignment.top]
}
}
static let xAlignment = VerticalAlignment(XAlignment.self)
}
struct ContentView: View {
@State var isOn: Bool = true
@State var c1: Color = Color(red: 1.00, green: 0.75, blue: 0.75)
@State var c2: Color = Color(red: 0.75, green: 1.00, blue: 0.75)
@State var c3: Color = Color(red: 1.00, green: 1.00, blue: 0.00)
@State var c4: Color = Color(red: 0.80, green: 1.00, blue: 0.75)
@State var c5: Color = Color(red: 0.75, green: 0.75, blue: 0.25)
var body: some View {
HStack(alignment: .xAlignment) {
Spacer()
Toggle(isOn: $isOn) {
Text("Hello")
.background(isOn ? c1 : .clear)
}
.background(isOn ? c2 : .clear)
.alignmentGuide(.xAlignment) { $0.height * 0.5 }
Text("The quick brown fox jumped over the lazy dog")
.background(isOn ? c3 : .clear)
.alignmentGuide(.xAlignment) {
($0.height - ($0[.lastTextBaseline] - $0[.firstTextBaseline])) * 0.5
}
Spacer()
Button("Go") {
print("Knock knock.")
}
.background(isOn ? c4 : .clear)
.alignmentGuide(.xAlignment) { $0.height * 0.5 }
Spacer()
}
.background(isOn ? c5 : .clear)
.padding()
}
}