SwiftUI:如何对齐位于不同视图容器中的两个元素

4

我在不同的容器视图中水平对齐两个元素时遇到了困难。我想要将两个分数(用红色表示)水平对齐。我尝试使用自定义对齐指南(和自定义坐标系),虽然这确实对齐了两个分数,但它也导致相应的堆栈发生了变化。我错过了什么?肯定有一种简单的方法来完成这个任务。

struct ContentViewExample: View {
    var body: some View {
        VStack(alignment: .leading) {
            HStack {
                Label("Team 1", systemImage: "seal")
                    .font(.title3)
                Spacer()
                Text("65")
                    .background(Color.red)
                Text("Final")
                    .font(.caption)
                    .padding(.leading)
            }
            HStack {
                Label("Team No 2", systemImage: "seal")
                    .font(.title3)
                Spacer()
                Text("70")
                    .background(Color.red)
            }
        }.padding(.horizontal)
    }
}

enter image description here


这个回答解决了你的问题吗?https://stackoverflow.com/a/63761269/12299030 - Asperi
在第二个HStack中添加另一个Text("Final"),并将其设置为.opacity(0)。 - nicksarno
3个回答

2

我的解决方案是使用一个(懒惰的?)VGrid:

struct Result : Identifiable, Hashable {
    var id = UUID()
    var name: String
    var label: String 
    var score: Int
    var final: Bool
}
var finalScore = [Result(name: "Team 1", label: "seal.fill", score: 167, final: true),
                  Result(name: "Team No 2", label: "seal", score: 65, final: false)]

struct ContentView: View {
    private var columns: [GridItem] = [
        GridItem(alignment: .leading),
        GridItem(alignment: .trailing),
        GridItem(alignment: .leading)
    ]
    
    var body: some View {
            LazyVGrid(
                columns: columns,
                alignment: .center,
                spacing: 16,
                pinnedViews: [.sectionHeaders, .sectionFooters]
            ) {
                Section(header: Text("Results").font(.title)) {
                    ForEach(finalScore) { thisScore in
                        Label(thisScore.name, systemImage: thisScore.label)
                            .background(Color(UIColor.secondarySystemBackground))
                        Text(String(thisScore.score))
                            .background(Color(UIColor.secondarySystemBackground))
                        Text(thisScore.final == true ? "Final" : "")
                            .background(Color(UIColor.secondarySystemBackground))
                    }
                }
            }
            .border(Color(.blue))
    }
}

在SwiftUI Playground中预览

不过需要调整颜色,我只是添加了一些背景和边框来确定位置... 如果需要的话,可能要优化列的宽度。 关于网格布局,建议阅读这篇文章:https://swiftwithmajid.com/2020/07/08/mastering-grids-in-swiftui/

顺便说一句:自定义对齐方式不起作用,因为整个HStack都会向左或向右移动,你必须调整那里的“列”的宽度,这会增加额外的麻烦。


1
我决定写一篇medium.com文章来回答这个问题,并已经完成了。以下是解决方案的样子,以及代码。这是文章和解决方案。

https://marklucking.medium.com/a-real-world-alignment-challenges-in-swiftui-2-0-ff440dceae5a

简而言之,我设置了四个标签的正确对齐方式,然后将这四个容器相互对齐。
在此代码中,我包含了一个滑块,以便您更好地理解它的工作原理。

enter image description here

import SwiftUI

struct ContentView: View {
private var newAlignment1H: HorizontalAlignment = .leading
private var newAlignment1V: VerticalAlignment = .top
private var newAlignment2H: HorizontalAlignment = .trailing
private var newAlignment2V: VerticalAlignment = .top

@State private var zeroX: CGFloat = 160

var body: some View {

    VStack {
        ZStack(alignment: .theAlignment) {
            HStack {
                Label {
                    Text("Team 1")
                        .font(.system(size: 16, weight: .semibold, design: .rounded))
                } icon: {
                    Image(systemName:"seal")
                        .resizable()
                        .scaledToFit()
                        .frame(width: 30)
                }.labelStyle(HorizontalLabelStyle())
            }
            .border(Color.blue)
            .alignmentGuide(.theHorizontalAlignment, computeValue: {d in zeroX})
//              .alignmentGuide(.theHorizontalAlignment, computeValue: {d in d[self.newAlignment2H]})
//              .alignmentGuide(.theVerticalAlignment, computeValue: {d in d[self.newAlignment1V]})
                HStack {
                    Text("65")
                        .font(.system(size: 16, weight: .semibold, design: .rounded))
                        .background(Color.red.opacity(0.2))
                        .frame(width: 128, height: 32, alignment: .trailing)
                        
                    Text("Final")
                        .font(.system(size: 16, weight: .semibold, design: .rounded))
                        .background(Color.red.opacity(0.2))
                        .frame(width: 48, height: 32, alignment: .leading)
                        
                }
                .border(Color.green)
        }
        
        ZStack(alignment: .theAlignment) {
            HStack {
                Label {
                    Text("Team No 2")
                        .font(.system(size: 16, weight: .semibold, design: .rounded))
                } icon: {
                    Image(systemName:"seal")
                        .resizable()
                        .scaledToFit()
                        .frame(width: 30)
                }.labelStyle(HorizontalLabelStyle())
                
            }
//                .alignmentGuide(.theHorizontalAlignment, computeValue: {d in d[self.newAlignment2H]})
//                .alignmentGuide(.theVerticalAlignment, computeValue: {d in d[self.newAlignment1V]})
            .alignmentGuide(.theHorizontalAlignment, computeValue: {d in zeroX})
            .border(Color.pink)
            
            HStack {
                Text("70")
                    .font(.system(size: 16, weight: .semibold, design: .rounded))
                    .background(Color.red.opacity(0.2))
                    .frame(width: 128, height: 32, alignment: .trailing)
                Text("")
                    .background(Color.red.opacity(0.2))
                    .frame(width: 48, height: 32, alignment: .leading)
            }
            .border(Color.orange)
        }
        
        VStack {
            Slider(value: $zeroX, in: 0...200, step: 10)
            Text("\(zeroX)")
        }
        
    }
    
    
}
}



struct VerticalLabelStyle: LabelStyle {
func makeBody(configuration: Configuration) -> some View {
    VStack(alignment: .center, spacing: 8) {
        configuration.icon
        configuration.title
    }
}
}

struct HorizontalLabelStyle: LabelStyle {
func makeBody(configuration: Configuration) -> some View {
    HStack(alignment: .center, spacing: 8) {
        configuration.icon
        configuration.title
    }
}
}

extension VerticalAlignment {
private enum TheVerticalAlignment : AlignmentID {
    static func defaultValue(in d: ViewDimensions) -> CGFloat {
        return d[VerticalAlignment.top]
    }
}

static let theVerticalAlignment = VerticalAlignment(TheVerticalAlignment.self)
}

extension HorizontalAlignment {
private enum TheHorizontalAlignment : AlignmentID {
    static func defaultValue(in d: ViewDimensions) -> CGFloat {
        return d[HorizontalAlignment.leading]
    }
}

static let theHorizontalAlignment = HorizontalAlignment(TheHorizontalAlignment.self)
}

extension Alignment {
static let theAlignment = Alignment(horizontal: .theHorizontalAlignment, vertical: .theVerticalAlignment)
}


struct ContentView_Previews: PreviewProvider {
static var previews: some View {
    ContentView()
}
}

-1

这里有一个可能的方法(类似于列式

demo

    HStack {
        // image column
        VStack {
            Image(systemName: "seal")
            Image(systemName: "seal")
        }
        .font(.title3)

        // text column
        VStack(alignment: .leading) {
            Text("Team 1")
            Text("Team No 2")
        }
        .font(.title3)
        Spacer()

        // score column
        VStack {
            Text("65")
            Text("70")
        }
        .background(Color.red)

        // note column
        VStack {
            Text("Final")
            Text("")
        }
        .font(.caption)
        .padding(.leading)
    }
    .frame(maxWidth: .infinity)
    .padding(.horizontal)

我已经对你的答案进行了相当多的评论,但是这仍然不是正确的解决方案。只需将字体添加到你的“Team 1”文本中,如.font(.system(size: 80)),你就会看到你的解决方案是无效的。再次强调,没有人强迫你回答所有这些问题。如果你不知道答案,请不要在答案中发垃圾信息。 - Farid

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接