Swiftui 在懒洋洋的大头钉内的嵌套ForEach上撞车
我有两个嵌套的Swiftui 在懒洋洋的大头钉内的嵌套ForEach上撞车,swiftui,swiftui-foreach,identifiable,Swiftui,Swiftui Foreach,Identifiable,我有两个嵌套的ForEachs在LazyHStack LazyHStack { ForEach(items) { item in ForEach(item.urls, id: \.self) { Text($0.absoluteString) } } } 此代码段可以编译,但会立即崩溃,并出现以下错误 致命错误:每个布局项只能出现一次:文件SwiftUI,第0行 我在网上读到,这可能是因为ForEach没有正确区分集合中的
ForEach
s在LazyHStack
LazyHStack {
ForEach(items) { item in
ForEach(item.urls, id: \.self) {
Text($0.absoluteString)
}
}
}
此代码段可以编译,但会立即崩溃,并出现以下错误
致命错误:每个布局项只能出现一次:文件SwiftUI,第0行
我在网上读到,这可能是因为ForEach
没有正确区分集合中的元素,即使所有元素都是可识别的。在我的例子中,外部ForEach
中的项
都是可识别的,而内部ForEach
则在可选URL?
对象数组中循环。我试图使用其绝对字符串(我认为应该是唯一的)来识别URL
,但没有成功
extension URL: Identifiable {
var id: String? { absoluteString }
}
我应该补充一点,相同的代码片段可以很好地用于标准的
HStack
。如何解决此问题?它正在工作,您在代码中有一些错误:
例如,您应该在扩展名中使用self
另外,你无缘无故地一起使用了2个ForEach inside,我会说编码不好,我不会建议一起使用2个ForEach inside,这会导致系统和你的应用程序崩溃,使用1个ForEach!然而,以下是你的答案:
用户界面的具体布局取决于您,但这个答案创建了一个水平滚动的URL列表,这些URL作为每个项目的一部分垂直堆叠 工作代码:
ScrollView(.horizontal) {
LazyHStack {
ForEach(items) { item in
VStack {
ForEach(item.urls) {
Text($0.absoluteString)
}
}
}
}
}
变化:
LazyHStack
包装在ScrollView
中,以便可以滚动屏幕外的项目以查看ForEach
s之间插入VStack
,以确定每个项目的布局
ForEach
中删除了id:\.self
,因为您已经为URL创建了自定义id
。使用id:\.id
或在ForEach
中不包含id
参数LazyHStack
存在一个问题,即ID并不都是唯一的。链接到类似的答案。这是另一种修复方法,不需要在以下两者之间使用VStack
:
Text($0.absoluteString)
.id(item.id.uuidString + ($0.id ?? ""))
编辑以支持可选URL
数据结构(这里唯一的区别是URL
被URLItem
替换,因此我们可以保留一个可选值):
新示例数据:
let items: [Item] = [
Item(urls: [
URLItem(URL(string: "https://www.google.com")), URLItem(URL(string: "https://www.stackoverflow.com"))
]),
Item(urls: [
URLItem(URL(string: "https://www.stackoverflow.com")), URLItem(URL(string: ""))
])
]
这意味着我们现在可以有可识别的可选URL。代码现在应该如下所示:
ForEach(item.urls) {
if let url = $0.url {
Text(url.absoluteString)
.id($0.id)
} else {
Text("Bad URL")
.id($0.id)
}
}
您现在可以处理自己的情况,其中$0.url
为nil
您可能有多个absoluteString
。请尝试var id:UUID{UUID()}
我不认为这是一个问题,而应用程序在运行时是智能的。。。你想要实现什么?如果在每个S的中间没有一个堆栈,那么应用程序崩溃是有意义的,因为它不知道如何为每个WHLIN除了“@ MADIBM”的注释之外布置第二个,也可以用<代码> >标识<代码> URL。而不是\.id
或将id
参数保留为空。谢谢您的回答。嵌套堆栈对于我的用例来说是一个很好的解决方案,但是我仍然有问题,因为URL
数组包含可选值。在这种情况下,编译器返回以下错误:“ForEach”上引用初始值设定项“init(uuz:content:)”要求“URL”符合“可识别”。@Dree您希望如何处理可选URL?您想不显示它们,显示一些替代文本,如“无URL”,还是以其他方式?你能保证这些URL不是零吗?例如,如果您只是不想显示nil
URL,您可以在item.url
之后使用.compactMap{$0}
来删除nil
值。如果文本
的ID有问题,您可以改为执行.ID(UUID())
。在ForEach
中,不仅有一个简单的文本
视图,还有另一个视图负责处理URL的nil情况。不幸的是,我不能仅仅使用compactMap
删除nil值@Dree code现在更新为支持可选URL。
let items: [Item] = [
Item(urls: [
URLItem(URL(string: "https://www.google.com")), URLItem(URL(string: "https://www.stackoverflow.com"))
]),
Item(urls: [
URLItem(URL(string: "https://www.stackoverflow.com")), URLItem(URL(string: ""))
])
]
ForEach(item.urls) {
if let url = $0.url {
Text(url.absoluteString)
.id($0.id)
} else {
Text("Bad URL")
.id($0.id)
}
}