我使用ForEach来显示数组的内容,然后通过判断元素索引手动显示每个元素之间的分隔符.这是我的代码:

struct ContentView: View {
    let animals = ["Apple", "Bear", "Cat", "Dog", "Elephant"]

    var body: some View {
        VStack {
            /// array of tuples containing each element's index and the element itself
            let enumerated = Array(zip(animals.indices, animals))
            ForEach(enumerated, id: \.1) { index, animal in
                Text(animal)

                /// add a divider if the element isn't the last
                if index != enumerated.count - 1 {
                    Divider()
                        .background(.blue)
                }
            }
        }
    }
}

结果:

Stack of text with dividers in between

这是可行的,但我希望有一种方法可以自动在任何地方添加除数,而不必每次都写Array(zip(animals.indices, animals)).以下是我目前掌握的情况:

struct ForEachDividerView<Data, Content>: View where Data: RandomAccessCollection, Data.Element: Hashable, Content: View {
    var data: Data
    var content: (Data.Element) -> Content

    var body: some View {
        let enumerated = Array(zip(data.indices, data))
        ForEach(enumerated, id: \.1) { index, data in

            /// generate the view
            content(data)

            /// add a divider if the element isn't the last
            if let index = index as? Int, index != enumerated.count - 1 {
                Divider()
                    .background(.blue)
            }
        }
    }
}

/// usage
ForEachDividerView(data: animals) { animal in
    Text(animal)
}

这非常有效,隔离了所有样板zip代码,仍然得到相同的结果.然而,这只是因为animals是一个String的数组,它符合Hashable-如果我的数组中的元素不符合Hashable,它将不起作用:

struct Person {
    var name: String
}

struct ContentView: View {
    let people: [Person] = [
        .init(name: "Anna"),
        .init(name: "Bob"),
        .init(name: "Chris")
    ]

    var body: some View {
        VStack {

            /// Error! Generic struct 'ForEachDividerView' requires that 'Person' conform to 'Hashable'
            ForEachDividerView(data: people) { person in
                Text(person.name)
            }
        }
    }
}

这就是为什么SwiftUI的ForEach附带了一个附加的初始值设定项init(_:id:content:),该初始值设定项采用自定义密钥路径来提取ID.我想在ForEachDividerView中利用这个初始值设定项,但我想不出来.以下是我try 的内容:

struct ForEachDividerView<Data, Content, ID>: View where Data: RandomAccessCollection, ID: Hashable, Content: View {
    var data: Data
    var id: KeyPath<Data.Element, ID>
    var content: (Data.Element) -> Content

    var body: some View {
        let enumerated = Array(zip(data.indices, data))

        /// Error! Invalid component of Swift key path
        ForEach(enumerated, id: \.1.appending(path: id)) { index, data in

            content(data)

            if let index = index as? Int, index != enumerated.count - 1 {
                Divider()
                    .background(.blue)
            }
        }
    }
}


/// at least this part works...
ForEachDividerView(data: people, id: \.name) { person in
    Text(person.name)
}

我try 使用appending(path:)将第一个键路径(从enumerated中提取元素)与第二个键路径(从元素中获取Hashable属性)组合起来,但得到了Invalid component of Swift key path.

如何在ForEach的元素之间自动添加分隔符,即使元素不符合Hashable

推荐答案

每件事都需要事先准备好吗?如果没有,您可以考虑根本不使用索引:

struct ForEachDividerView<Data, Content, ID>: View where Data: RandomAccessCollection, ID: Hashable, Content: View {
    var data: Data
    var id: KeyPath<Data.Element, ID>
    var content: (Data.Element) -> Content
    
    var body: some View {
        if let first = data.first {
            content(first)
            
            ForEach(data.dropFirst(), id: id) { element in
                Divider()
                    .background(.blue)
                content(element)
            }
        }
    }
}

Ios相关问答推荐

实例方法wait在异步上下文中不可用;请改用TaskGroup;这是Swift 6中的错误''

在SWIFT中将圆角+透明背景从导入视频(.mp4)添加到导出视频(.mov)

UIAlertController的空子类是否可以与`appearance(whenContainedInInstancesOf:)`一起安全使用

由于已存在同名项目,因此无法将Mapbox.xcframework-ios.sign复制到Signature中

如何在iOS 17 SwiftUI中获取用户名

如何通过点击按钮滚动到 ScrollView 中的特定视图?

iOS 16 中的状态栏 colored颜色

使用 AVCaptureDeviceTypeBuiltInTripleCamera 时 Select 合适的相机进行条码扫描

UIView 倒置旋转时的zoom 问题

xcode-select:找不到clang

通过 Rosetta 打开模拟器 xcode 14 以修复滚动

为 ColorPicker 创建一个名为 Color 的计算变量的绑定

我可以在 Apple-Watch 上使用 iPhone 的摄像头扫描 SwiftUi 中的二维码(例如用于登录)吗

有哪些可靠的机制可以防止 CoreData CloudKit 中的数据重复?

如何避免任何绑定空错误并更好地获取代码

Xcode - 错误 ITMS-90635 - Bundle 包中的 Mach-O 无效 - 提交到 App Store

如何关闭情节提要弹出框

如何在键盘上方添加工具栏?

Parse for iOS:try 运行应用程序时出错

以编程方式确定 iPhone 是否越狱