我在视图中有一个HStack,它应该显示视图内容,所有元素之间都有空格:

import SwiftUI

struct ContentView: View {
    
    var element_1: some View {
        Circle()
            .frame(width: 50, height: 50)
    }
    
    var element_2: some View {
        Circle()
            .frame(width: 50, height: 50)
    }
    
    var element_3: some View {
        Circle()
            .frame(width: 50, height: 50)
    }
    
    var body: some View {
        HStack {
            Spacer()
            element_1
            Spacer()
            element_2
            Spacer()
            element_3
            Spacer()
        }
    }
}

其显示了以下内容:

然而,当有更多的视图(Element_1、Element_2、...、Element_7)时,HStack变得有点难以读取,因为HStack中有太多的Spacer()个,需要进行一些重构:

// Example of having 7 element Views, with 8 spacers in:

HStack {
    Spacer()
    element_1
    Spacer()
    element_2
    Spacer()
    element_3
    Spacer()
    element_4
    Spacer()
    element_5
    Spacer()
    element_6
    Spacer()
    element_7
    Spacer()
}

我曾try 实现一个定制SpacedHStack来实现相同的输出,以便将HStack减少到

SpacedHStack {
    element_1
    element_2
    element_3
    element_4
    element_5
    element_6
    element_7
}

使用以下 struct :

struct SpacedHStack<Content: View>: View {
    var views: [Content]

    init(@ViewBuilder content: @escaping () -> Content) {
        self.views = [content()]
    }

    var body: some View {
        HStack(spacing: 0) {
            ForEach(views.indices, id: \.self) { index in
                views[index]
                if index != views.count - 1 {
                    Spacer()
                }
            }
        }
    }
}

但输出结果与之前的HStack不同,该HStack具有n+1个间隔符和n个元素视图:

之前实现的n个元素的n+1个间隔物有助于使元素能够根据iPad的任何尺寸进行定位,而设定的长度HStack(spacing: 30){ ... }是不可行的(不幸的是,没有HStack(spacing: Spacer()) { ... }这样的东西).然而,由于HStack中有许多Spacer()‘S,这使得代码更难阅读.在定制SpacedHStack中可以做什么来获得与先前所做的相同的输出?或者,有没有一种优雅的解决方案来重构HStack,使其不需要定制的SpacedHStack struct ?

推荐答案

如果只想减少所有Spacer()占用的垂直屏幕空间,可以将其提取到视图修改器中:

extension View {
    @ViewBuilder
    func withSpacer() -> some View {
        self
        Spacer()
    }
}

然后可以添加"内联"的间隔符:

HStack {
    Spacer()
    element_1.withSpacer()
    element_2.withSpacer()
    element_3.withSpacer()
    element_4.withSpacer()
    element_5.withSpacer()
    element_6.withSpacer()
    element_7.withSpacer()
}

否则,如果您不介意使用带下划线前缀的API,您可以使用View Extractor提取ViewBuilder中的每个视图.

struct HStackWithSpacers<Content: View>: View {
    let content: Content
    
    init(@ViewBuilder content: @escaping () -> Content) {
        self.content = content()
    }
    
    var body: some View {
        HStack {
            ExtractMulti(content) { views in
                ForEach(views) { view in
                    view
                    Spacer()
                }
            }
        }
    }
}

Swift相关问答推荐

按变换zoom 在UIView中不起作用

NSWindow中以编程方式创建的TextField快捷方式与SwiftUI

查找数组中 ** 元素 ** 的属性的最小值和最大值

我可以为UIMenu设定一个固定的订单吗?

在 SwiftUI 视图中观察 UIViewRepresentable 的 @State var 变化

使用 @resultBuilder 的通用 buildList 函数

在SwiftUI中使用ForEach循环来显示字典项的键和值在Form视图中

SwiftUI路径平滑连接两条线

如何在闭包中使用构造 await sync

子视图未在父视图 SwiftUI 中触发禁用状态更新

为什么 String.contains 在我导入 Foundation 时表现不同?

签署GoogleSignIn-GoogleSignIn需要开发团队

Swift 中的Combine和didSet有什么区别?

您可以在运行时访问 Picker 元素并更改它们的 colored颜色 吗

为什么 switch 在 optional 中不接受 case nil?

Swift:连接两个数组而不重复共享后缀/前缀

在视图中设置所有变量

为什么'nil' 与 Swift 3 中的 'UnsafePointer' 不兼容?

将活动指示器 colored颜色 更改为黑色

键盘显示时Tableview滚动内容