正确布局 SwiftUI 的方法(类似于 Autolayout)

Correct way to layout SwiftUI (similar to Autolayout)

问题:

我正在努力使用 SwiftUI 有效地布局视图。 我对 UIKit 和 Autolayout 非常熟悉,总觉得它很直观。

我知道 SwiftUI 还很年轻,才刚刚起步,所以可能我期望太高了,但举个简单的例子:

假设我有 HStackText() 次观看。

|--------------------------------|
| Text("static") Text("Dynamic") |  
|________________________________|

当我有 动态 内容时,静态 文本字符串随着 HStack 的大小到处跳动改变,当 Text("Dynamic") 改变时...

我尝试了很多东西,Spacers()Dividers(),研究了使用 PreferenceKeys (link), Alignment Guides (link)

的方法

最接近答案的似乎是对齐指南,但它们很复杂。

复制 Autolayout 基本将视图锚定在屏幕边缘附近并正确布局而无需跳转的能力的规范方法是什么?

我想锚定静态文本“纬度”,这样它就不会跳来跳去。

还有其他示例,因此我们希望能提供一个关于如何最好地布局的更一般的答案...

有了 Autolayout,感觉我选择了一切顺利。使用 SwiftUI 就像彩票一样。

示例,显示单词“Latitude”随着坐标变化而跳跃:

例子,代码:

HStack {
    Text("Latitude:")
    Text(verbatim: "\(self.viewModelContext.lastRecordedLocation().coordinate.latitude)")
}

当我的观点有 changing/dynamic 背景时,我真的很挣扎。如所有 WWDC 视频所示,静态内容一切正常。

可能的解决方案:

像这样使用 HStack

HStack(alignment: .center, spacing: 20) {
    Text("Latitude:")
    Text(verbatim: "\(self.viewModelContext.lastRecordedLocation().coordinate.latitude)")
    Spacer()
}
.padding(90)

结果很好地锚定了,但我讨厌神奇的数字。

正如您所发现的那样,第一步是您需要决定您想要什么。在这种情况下,您似乎想要 left-alignment (基于您的填充解决方案)。这很好:

    HStack {
        Text("Latitude:")
        Text(verbatim: "\(randomNumber)")
        Spacer()
    }

这将使 HStack 与其包含的视图一样宽,并将文本推到左侧。

但是从你后来的评论来看,你好像不想让它在最左边。在这种情况下,你必须准确地决定你想要什么。添加 .padding 会让您从左侧移动它(也许只添加 .leading),但也许您想将其与屏幕尺寸相匹配。

这是一种方法。重要的是要记住HStack的基本算法,就是给每个人他们的最小值,然后把剩下的space分给灵活的视图。

    HStack {
        HStack {
            Spacer()
            Text("Latitude:")
        }
        HStack {
            Text(verbatim: "\(randomNumber)")
            Spacer()
        }
    }

外面的 HStack 有 2 children,所有的人都可以灵活地降低到某个最小值,所以它为每个人提供相等数量的 space(总宽度的 1/2)如果它可以适应。

(我最初是用 2 个额外的垫片做的,但我忘记了垫片似乎有特殊的处理方式来让它们的 space 最后。)

问题是如果 randomNumber 太长会怎样?如所写,它会换行。或者,您可以添加 .fixedSize() 来阻止它换行(并将 Latitude 推到左侧以使其适合)。或者您可以添加 .lineLimit(1) 以强制它截断。由你决定。

但重要的是添加了灵活的 HStacks。如果每个 child 都是灵活的,那么它们都会得到相同的 space.

如果你想把东西强制成三分之一或四分之一,我发现你需要添加除垫片以外的东西。例如,这将给出纬度和可用数字的 1/4 space 而不是 1/2(注意添加 Text("")):

    HStack {
        HStack {
            Text("")
            Spacer()
        }
        HStack {
            Spacer()
            Text("Latitude:")
        }
        HStack {
            Text(verbatim: "\(randomNumber)")//.lineLimit(1)
            Spacer()
        }
        HStack {
            Text("")
            Spacer()
        }
    }

在我自己的代码中,我经常做这种事情,所以我有类似的东西

struct RowView: View {   
    // A centered column
    func Column<V: View>(@ViewBuilder content: () -> V) -> some View {
        HStack {
            Spacer()
            content()
            Spacer()
        }
    }

    var body: some View {
        HStack {
            Column { Text("Name") }
            Column { Text("Street") }
            Column { Text("City") }
        }
    }
}