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

Woo*_*ock 2 view ios autolayout swift swiftui

问题:

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

我知道 SwiftUI 还很年轻,才刚刚开始,所以也许我期望太多,但举一个简单的例子:

说我有一个HStack看法Text()

|--------------------------------|
| Text("static") Text("Dynamic") |  
|________________________________|
Run Code Online (Sandbox Code Playgroud)

当我有动态内容时,当文本(“动态”)发生变化时,静态文本字符串会随着大小的变化而跳遍各处HStack......

我尝试了很多东西,,,Spacers()查看Dividers()了使用PreferenceKeys链接),Alignment Guides链接)的方法

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

复制自动布局基本将视图锚定到屏幕边缘附近并正确布局而不跳来跳去的能力的规范方法是什么?

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

还有其他示例,因此我们将不胜感激有关如何最佳布局的更一般的答案......

使用自动布局,感觉我选择了一切顺利。对于 SwiftUI 来说就像是买彩票。

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

问题

示例,代码:

HStack {
    Text("Latitude:")
    Text(verbatim: "\(self.viewModelContext.lastRecordedLocation().coordinate.latitude)")
}
Run Code Online (Sandbox Code Playgroud)

当我的观点发生变化/动态背景时,我真的很挣扎。对于静态内容来说一切正常,如所有 WWDC 视频中所示。

潜在的解决方案:

使用HStack这样的:

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

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

Rob*_*ier 7

正如您所发现的,第一件事是您需要决定您想要什么。在这种情况下,您似乎想要左对齐(基于您的填充解决方案)。所以这样很好:

    HStack {
        Text("Latitude:")
        Text(verbatim: "\(randomNumber)")
        Spacer()
    }
Run Code Online (Sandbox Code Playgroud)

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

但从你后来的评论来看,你似乎不希望它位于最左边。在这种情况下,你必须准确地决定你想要什么。添加.padding将使您可以将其从左侧移入(也许.leading仅通过添加),但也许您希望将其与屏幕尺寸相匹配。

这是一种方法。重要的是要记住 HStack 的基本算法,即给每个人最小的空间,然后在灵活的视图之间分配剩余空间。

    HStack {
        HStack {
            Spacer()
            Text("Latitude:")
        }
        HStack {
            Text(verbatim: "\(randomNumber)")
            Spacer()
        }
    }
Run Code Online (Sandbox Code Playgroud)

外部 HStack 有 2 个子级,所有子级都可以灵活地降低到某个最小值,因此如果可以容纳的话,它会为每个子级提供等量的空间(总宽度的 1/2)。

(我最初用 2 个额外的垫片来做到这一点,但我忘记了垫片似乎有特殊的处理来获得最后的空间。)

问题是如果randomNumber太长会发生什么?正如所写,它会包裹起来。或者,您可以添加.fixedSize()这将阻止它换行(并将纬度推到左侧以使其适合)。或者您可以添加.lineLimit(1)以强制其截断。由你决定。

但重要的是灵活的HStack的加入。如果每个孩子都很灵活,那么他们都会得到相同的空间。

如果你想将事情强制到三分之一或四分之一,我发现你需要添加除间隔之外的其他东西。例如,这将给出纬度和可用空间的 1/4,而不是 1/2(注意添加Text("")):

    HStack {
        HStack {
            Text("")
            Spacer()
        }
        HStack {
            Spacer()
            Text("Latitude:")
        }
        HStack {
            Text(verbatim: "\(randomNumber)")//.lineLimit(1)
            Spacer()
        }
        HStack {
            Text("")
            Spacer()
        }
    }
Run Code Online (Sandbox Code Playgroud)

在我自己的代码中,我做了很多这样的事情,我有类似的事情

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") }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)