swiftui-自动在“ foreach”的每个元素之间添加分隔线
我正在使用 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)
}
}
}
}
}
结果:
这 有效,但是我希望一种方法可以在无需编写 array(Zip(Animal.Indices,Animal))
的情况下自动添加隔板。到目前为止,这是我到目前为止的:
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
代码,并且仍然获得相同的结果。但是,这仅仅是因为动物
是字符串
s的数组,它符合 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)
}
}
}
}
hashable“ rel =” nofollow noreferrer“> hashable
- 如果我的 Swiftui的 foreach
带有附加的初始化器, init(_:ID:content:)
,它会涉及提取ID的自定义密钥路径。我想在我的 foreachDividerView
中利用此初始化器,但我无法弄清楚。这是我尝试的方法:
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)
}
我尝试使用
appending(appending(路径)
将第一个关键路径(从
。枚举
中提取元素)与第二个密钥路径(从元素获取 hashable
属性),但是我得到了Swift密钥路径的无效组件
即使元素不符合
,我如何在 foreach 的元素之间自动添加一个分隔线?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
简单的方式
通常可以识别动物内部的类型。在这种情况下,代码将被修改为。
这将避免任何平等的要求/实现
Simple way
Typically the type inside animals must be Identifiable. In which case the code will be modified as.
This will avoid any equatable requirements/ implementations
使用评论中提到的文章我构建了以下内容。它采用一组视图,并在它们之间放置一个分隔线。
当视图不是由 foreach 生成的视图时,这也很有用,尤其是当有条件地删除一个或多个视图时(例如,使用语句使用)。
Using the article mentioned in a comment I built the following. It takes the set of views and places a divider between them.
This is also useful when the views are not being generated by a
ForEach
, especially when one or more of the views is removed conditionally (e.g. using anif
statement).一切都需要在foreach中吗?如果没有,您可以考虑根本不使用索引:
Does everything need to be in a ForEach? If not, you can consider not using indices at all:
找到了解决方案!
appending(pathending(path:)
似乎仅在删除到appending(path:)
返回一个可选anykeypath?
- 这需要降低到键>键>键> keypath&lt;(data.index,data.element),id&gt ;
满足id
参数。用法:
结果:
Found a solution!
appending(path:)
seems to only work on key paths erased toAnyKeyPath
.appending(path:)
returns an optionalAnyKeyPath?
— this needs to get cast down toKeyPath<(Data.Index, Data.Element), ID>
to satisfy theid
parameter.Usage:
Result: