Home > Blockchain >  Align only one object to the centre in an HStack
Align only one object to the centre in an HStack

Time:10-12

I'm trying to create a simple fixture list (a list of one team vs another team) in SwiftUI. The "vs" Text field needs to be centrally aligned on the screen with team1 immediately to the left of this and team2 immediately to the right. A simple example of this is shown in the image below. Note how vs always appears on the centre line and the team names are essentially leading or trailing aligned to the "vs" Text box...

enter image description here

If the 3 text items are aligned in a simple HStack, it is the sum width of these text fields which is aligned centrally on the screen and as such the "vs" Text field will wander from side to side on the screen.

I am confident I could create the desired effect above using geometry reader but this feels like it would be somewhat arduous and I was wondering if there is a simple alignment type or extension that could be used to create the desired effect?

CodePudding user response:

You can make use of alignment guides. This answer also centers the vs to the screen, not just relative to each other.

Code:

struct ContentView: View {
    private let games: [Game] = [
        Game("Manchester United", vs: "Arsenal"),
        Game("Liverpool", vs: "Newcastle United")
    ]

    var body: some View {
        ZStack(alignment: .centerVs) {
            Color.clear
                .frame(height: 0)
                .frame(maxWidth: .infinity)
                .alignmentGuide(.centerVs) { d in
                    d[HorizontalAlignment.center]
                }

            VStack(alignment: .centerVs) {
                ForEach(games) { game in
                    HStack {
                        Text(game.team1)

                        Text("vs")
                            .alignmentGuide(.centerVs) { d in
                                d[HorizontalAlignment.center]
                            }

                        Text(game.team2)
                    }
                }
            }
        }
    }
}
struct Game: Identifiable {
    let id = UUID()
    let team1: String
    let team2: String

    init(_ team1: String, vs team2: String) {
        self.team1 = team1
        self.team2 = team2
    }
}
extension HorizontalAlignment {
    private struct CenterVsAlignment: AlignmentID {
        static func defaultValue(in context: ViewDimensions) -> CGFloat {
            context[HorizontalAlignment.center]
        }
    }

    static let centerVs = HorizontalAlignment(CenterVsAlignment.self)
}

extension Alignment {
    static let centerVs = Alignment(horizontal: .centerVs, vertical: .center)
}

Result:

Result

  • Related