Как выровнять два элемента в разных представлениях по переднему краю в SwiftUI?

У меня есть эта специальная ячейка. Я попробовал другой подход для выравнивания «Диапазона навыков» и «Время», добавив .alignmentGuide(.leading) как к «Диапазону навыков», так и к «Времени», но, похоже, не работает. Как мне выровнять «Диапазон навыков» и «Время» в начале одной и той же ведущей точки? Как мне выровнять передний край «Диапазона навыков» с передним краем «Время»?

Я ответил на несколько вопросов, связанных с этим. Но не повезло!! Если бы кто-нибудь мог мне помочь, было бы здорово!

struct MatchInfoCell: View {
    // MARK: - Variables
    var matchListModel: MatchListModel
    var acceptButtonTitle: String? = "Accept Match"
    var acceptButtonAction: (()->Void)?
    
    var body: some View {
        VStack(alignment: .leading, spacing: 12) {
            HStack(spacing: 32) {
                VStack(alignment: .leading) {
                    // MARK: - Singles/Doubles
                    Text("Match Type")
                        .robotoRegularFont(size: 10)
                        .foregroundColor(Color.custom333333Color.opacity(0.5))
                    Text(self.matchListModel.singlesDoubles == "1" ? "Singles" : "Doubles")
                        .robotoMediumFont(size: 10)
                        .foregroundColor(Color.custom333333Color)
                }
                VStack(alignment: .leading) {
                    // MARK: - Skill Range
                    Text("Skill Range")
                        .robotoRegularFont(size: 10)
                        .foregroundColor(Color.custom333333Color.opacity(0.5))
                    Text("\(self.matchListModel.skillRangeMin) - \(self.matchListModel.skillRangeMax)")
                        .robotoMediumFont(size: 10)
                        .foregroundColor(Color.custom333333Color)
                }
                
                VStack(alignment: .leading) {
                    // MARK: - No of Participants
                    Text("Players")
                        .robotoRegularFont(size: 10)
                        .foregroundColor(Color.custom333333Color.opacity(0.5))
                    let combinedNames = self.matchListModel.nameOfParticipants
                        .filter { $0.firstName != "" && $0.lastName != "" }
                        .compactMap { "\($0.firstName) \($0.lastName.first ?? "a")" }
                    let str = combinedNames.joined(separator: ", ")
                    Text(str)
                        .robotoMediumFont(size: 10)
                        .foregroundColor(Color.custom333333Color)
                }
                .padding(.trailing)
            }
            VStack {
                HStack(spacing: 32) {
                    VStack(alignment: .leading) {
                        let dateStr = UtilityMethods.convertTimestampToDate(timestamp: TimeInterval(self.matchListModel.dateTime), format: E_D_MMM_YY)
                        // MARK: - Date
                        Text("Date:")
                            .robotoRegularFont(size: 10)
                            .foregroundColor(Color.custom333333Color.opacity(0.5))
                        Text(dateStr)
                            .robotoMediumFont(size: 10)
                            .foregroundColor(Color.custom333333Color)
                    }
                    
                    VStack(alignment: .leading) {
                        let timeStr = UtilityMethods.convertTimestampToDate(timestamp: TimeInterval(self.matchListModel.dateTime), format: HH_MM_A)
                        // MARK: - Time
                        Text("Time:")
                            .robotoRegularFont(size: 10)
                            .foregroundColor(Color.custom333333Color.opacity(0.5))
                        Text(timeStr)
                            .robotoMediumFont(size: 10)
                            .foregroundColor(Color.custom333333Color)
                    }
                }
            }
            Line()
                .stroke(style: StrokeStyle(lineWidth: 1, dash: [5]))
                .foregroundColor(Color.customCECECEColor)
                .frame(height: 1)
            
            HStack(spacing: 5) {
                // MARK: - Court
                Text("Court:")
                    .robotoRegularFont(size: 10)
                    .foregroundColor(Color.custom333333Color.opacity(0.5))
                Text(self.matchListModel.homeCourt)
                    .robotoMediumFont(size: 12)
                    .foregroundColor(Color.custom333333Color)
            }
            HStack {
                Spacer()
                
                // MARK: - Button Accept Match
                Button {
                    self.acceptButtonAction?()
                } label: {
                    Text(self.acceptButtonTitle ?? "")
                        .robotoMediumFont(size: 10)
                        .foregroundColor(.white)
                        .frame(width: 88, height: 30)
                        .background(Color.custom64B054Color)
                        .cornerRadius(5)
                }
            }
        }
        .padding(.all, 10)
        .frame(maxWidth: .infinity)
        .overlay(
            RoundedRectangle(cornerRadius: 9)
                .stroke(Color.custom64B054Color, lineWidth: 1)
        )
        .background(
            RoundedRectangle(
                cornerRadius: 9
            )
            .foregroundColor(Color.white)
            .shadow(
                color: Color.black.opacity(0.25),
                radius: 9,
                x: 0,
                y: 0
            )
        )
    }
}

88
2

Ответы:

Решено

VStack с подробностями содержит только метку и значение. Эти пары выровнены правильно: видно, что метки и значения выровнены по начальному краю.

Чтобы совместить записи во второй строке с записями в первой, я бы предложил переставить стопки:

вместо 2 HStack внутри VStack
используйте 3 VStack внутри HStack

VStack(alignment: .leading, spacing: 12) {
    HStack(alignment: .top, spacing: 32) {
        VStack(alignment: .leading, spacing: 12) {
            VStack(alignment: .leading) {
                // MARK: - Singles/Doubles
            }

            VStack(alignment: .leading) {
                // MARK: - Date
            }
        }

        VStack(alignment: .leading, spacing: 12) {
            VStack(alignment: .leading) {
                // MARK: - Skill Range
            }

            VStack(alignment: .leading) {
                // MARK: - Time
            }
        }

        VStack(alignment: .leading) {
            // MARK: - No of Participants
        }
    }
    Line()
    // content below line
}

Screenshot

Возможным преимуществом этого подхода по сравнению с сеткой является то, что последний столбец с именами игроков может иметь большую высоту, чем записи в первых двух столбцах, без смещения нижней строки вниз. Например, если имена игроков будут находиться в отдельных строках, дополнительные строки не приведут к изменению интервала в первых двух столбцах.


Используйте Grid. Вы можете установить alignmentGrid на .leading.

Вот пример:

Grid(alignment: .leading, horizontalSpacing: 32, verticalSpacing: 12) {
    GridRow {
        VStack(alignment: .leading) {
            Text("Match Type")
                .foregroundStyle(.secondary)
            Text("Doubles")
        }
        VStack(alignment: .leading) {
            Text("Skill Range")
                .foregroundStyle(.secondary)
            Text("1.25-2.25")
        }
        VStack(alignment: .leading) {
            Text("Players")
                .foregroundStyle(.secondary)
            Text("Dimpy P")
        }
    }
    GridRow {
        VStack(alignment: .leading) {
            Text("Date")
                .foregroundStyle(.secondary)
            Text("Thu, 1 Jan 70")
        }
        VStack(alignment: .leading) {
            Text("Time")
                .foregroundStyle(.secondary)
            Text("5:30 AM")
        }
        .gridCellColumns(2)
    }
    GridRow {
        (Text("Court: ").foregroundStyle(.secondary) + Text("Snape Park"))
            .gridCellColumns(3)
    }
}

Используйте gridCellColumns, чтобы разделы «Время» и «Суд» заполняли оставшееся пространство в соответствующих строках.