在一个 SwiftUI 视图中两次相同的 ForEach 循环
Same ForEach loop twice in one SwiftUI View
当我在视图中对数组使用 ForEach 循环两次时,我在运行时收到以下警告:
LazyVGridLayout: the ID 84308994-9D16-48D2-975E-DC40C5F9EFFF is used by multiple child views, this will give undefined results!
到目前为止,原因很清楚,但是解决这个问题的最明智的方法是什么?
下面的示例代码说明了这个问题:
import SwiftUI
// MARK: - Model
class Data: ObservableObject
{
@Published var items: [Item] = [Item(), Item(), Item()]
}
struct Item: Identifiable
{
let id = UUID()
var name: String = ""
var description: String = ""
}
// MARK: - View
struct MainView: View {
@StateObject var data: Data
private var gridItems: [GridItem] { Array(repeating: GridItem(), count: data.items.count) }
var body: some View {
LazyVGrid(columns: gridItems, alignment: .leading, spacing: 2) {
ForEach(data.items) { item in
Text(item.name)
}
ForEach(data.items) { item in
Text(item.description)
}
}
}
}
// MARK: - App
@main
struct SwiftUI_TestApp: App {
var body: some Scene {
WindowGroup {
MainView(data: Data())
}
}
}
我可以将视图分成几个子视图。
还有其他选择吗?
编辑:
这是 真实 应用程序的主体:
var body: some View {
VStack {
LazyVGrid(columns: columns, alignment: .leading, spacing: 2) {
Text("")
ForEach($runde.players) { $player in
PlayerHeader(player: $player)
}
ForEach(Score.Index.allCases) { index in
Text(index.localizedName)
ForEach(runde.players) { player in
Cell(player: player, active: player == runde.activePlayer, index: index)
}
}
Text ("")
ForEach(runde.players) { player in
PlaceView(player: player)
}
}
.padding()
}
}
如果你真的需要那种网格填充,那么可以为那些 ForEach
容器使用不同的标识符,比如
LazyVGrid(columns: gridItems, alignment: .leading, spacing: 2) {
ForEach(data.items) { item in
Text(item.name).id("\(item.id)-1") // << here !!
}
ForEach(data.items) { item in
Text(item.description).id("\(item.id)-2") // << here !!
}
}
使用 Xcode 13beta / iOS 15
测试
虽然在 ForEach 循环中添加标识符有时可行,但我发现在其他情况下使用索引访问循环中的索引也可行:
ForEach(items.indices, id: \.self) { i in
Text(items[i])
}
当我在视图中对数组使用 ForEach 循环两次时,我在运行时收到以下警告:
LazyVGridLayout: the ID 84308994-9D16-48D2-975E-DC40C5F9EFFF is used by multiple child views, this will give undefined results!
到目前为止,原因很清楚,但是解决这个问题的最明智的方法是什么?
下面的示例代码说明了这个问题:
import SwiftUI
// MARK: - Model
class Data: ObservableObject
{
@Published var items: [Item] = [Item(), Item(), Item()]
}
struct Item: Identifiable
{
let id = UUID()
var name: String = ""
var description: String = ""
}
// MARK: - View
struct MainView: View {
@StateObject var data: Data
private var gridItems: [GridItem] { Array(repeating: GridItem(), count: data.items.count) }
var body: some View {
LazyVGrid(columns: gridItems, alignment: .leading, spacing: 2) {
ForEach(data.items) { item in
Text(item.name)
}
ForEach(data.items) { item in
Text(item.description)
}
}
}
}
// MARK: - App
@main
struct SwiftUI_TestApp: App {
var body: some Scene {
WindowGroup {
MainView(data: Data())
}
}
}
我可以将视图分成几个子视图。
还有其他选择吗?
编辑:
这是 真实 应用程序的主体:
var body: some View {
VStack {
LazyVGrid(columns: columns, alignment: .leading, spacing: 2) {
Text("")
ForEach($runde.players) { $player in
PlayerHeader(player: $player)
}
ForEach(Score.Index.allCases) { index in
Text(index.localizedName)
ForEach(runde.players) { player in
Cell(player: player, active: player == runde.activePlayer, index: index)
}
}
Text ("")
ForEach(runde.players) { player in
PlaceView(player: player)
}
}
.padding()
}
}
如果你真的需要那种网格填充,那么可以为那些 ForEach
容器使用不同的标识符,比如
LazyVGrid(columns: gridItems, alignment: .leading, spacing: 2) {
ForEach(data.items) { item in
Text(item.name).id("\(item.id)-1") // << here !!
}
ForEach(data.items) { item in
Text(item.description).id("\(item.id)-2") // << here !!
}
}
使用 Xcode 13beta / iOS 15
测试虽然在 ForEach 循环中添加标识符有时可行,但我发现在其他情况下使用索引访问循环中的索引也可行:
ForEach(items.indices, id: \.self) { i in
Text(items[i])
}