Assume I build a view like this:
struct MyView: View {
@State private var a: String
@State private var b: String
@State private var c: String
var body: some View {
VStack {
HStack {
Text(a)
// this is the central view
Text(b).font(.headline)
}
Text(c)
}
}
}
I would like the central text view (the one displaying b) to be the anchor of the layout. That is, no matter how other text values change, I would like the central text to always stay in the centre of MyView (the centre of the text element and the centre of MyView should stay identical) and the other text elements should be laid out around the central one.
How to I achieve this? I tried to look at alignment guides, but I just don't seem to understand how to use them properly.
After spending some time to learn how alignment works in detail, I managed to arrive at a solution that only uses stacks and custom alignments, with minimal alignment guides and without needing to save any intermediate state. It's purely declarative, so I am supposed this is how SwiftUI designers intended it. I still think that there might have been a better design for it, but one can work with it.
struct ContentView: View {
@State var a: String = "AAAAA"
@State var b: String = "BBBB"
@State var c: String = "CCCCCC"
var body: some View {
VStack {
ZStack(alignment: .mid) {
// create vertical and horizontal
// space to align to
HStack { Spacer() }
VStack { Spacer() }
VStack(alignment: .midX) {
Text(self.a)
HStack(alignment: .center) {
Text(self.c)
Text(self.b)
.font(.title)
.border(Color.blue)
.alignmentGuide(.midX) { d in
(d[.leading] + d[.trailing])/2
}
.alignmentGuide(.midY) { d in
(d[.top] + d[.bottom])/2
}
}
}
}
.layoutPriority(1.0)
.overlay(CrossHair().stroke(Color.pink, lineWidth: 2))
TextField("", text: self.$b).textFieldStyle(RoundedBorderTextFieldStyle())
}
}
}
fileprivate extension HorizontalAlignment {
enum MidX : AlignmentID {
static func defaultValue(in d: ViewDimensions) -> CGFloat {
return (d[.leading] + d[.trailing])/2
}
}
static let midX = HorizontalAlignment(MidX.self)
}
fileprivate extension VerticalAlignment {
enum MidY : AlignmentID {
static func defaultValue(in d: ViewDimensions) -> CGFloat {
return (d[.top] + d[.bottom])/2
}
}
static let midY = VerticalAlignment(MidY.self)
}
fileprivate extension Alignment {
static let mid = Alignment(horizontal: .midX, vertical: .midY)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With