0

SwiftUI 的新手,并尝试在 LazyVGrid 内的单独 CardViews 上显示这些表情符号。当我使用 ForEach 循环为每个 CardView 设置一个表情符号时,我不能使用重复的表情符号 - 即使我使用过id: \.self(实际上,并不完全确定这对我想要实现的目标很重要,但认为值得一提)。

基本上,我可以显示 5 张卡片,但是当我尝试显示 6 张(即重复项目开始时)时,预览会崩溃。我可以用 HStack 做到这一点,但由于某种原因,不能用 LazyVStack。我查看了 LazyVStack 文档,但找不到答案。

此外,尝试在 ForEach 中使用 .indicies 但似乎也没有修复它。

import SwiftUI

struct ContentView: View {
    var emojis: [String] = ["", "", "", "",
                            "", "", "", "",
                            "", "", "", "",
                            "", "", "", "",
                            "", "", "", "",
                            "", "", "", ""]
    @State var emojiCount = 5 //6
    
    var gridLayout = [GridItem(), GridItem(), GridItem()]
    
    var body: some View {
        VStack {
            LazyVGrid(columns: gridLayout) {
//            HStack {
                ForEach((emojis[0..<emojiCount]), id: \.self) { emoji in
                    CardView(content: emoji)
                }
            }
            .foregroundColor(.red)

            Spacer()
            
            HStack {
                remove
                Spacer()
                add
            }
        }
        .padding(.horizontal)
    }
    
    var add: some View {
        Button(action: {
            emojiCount += 1
        }, label: {
            Text("⨁&quot;)
        })
    }

    var remove: some View {
        Button(action: {
            if emojiCount > 0 {
                emojiCount -= 1
            }
        }, label: {
            Text("⊖&quot;)
        })
    }
}

struct CardView: View {
    var content: String
    @State var isFaceUp: Bool = true
    
    var body: some View {
        ZStack {
            let shape = RoundedRectangle(cornerRadius: 20.0)
            if isFaceUp {
                shape.fill().foregroundColor(.white)
                shape.stroke(lineWidth: 3.0)
                Text(content)
            } else {
                shape.fill()
            }
        }
        .onTapGesture {
            isFaceUp = !isFaceUp
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
            .preferredColorScheme(.dark)
        ContentView()
            .preferredColorScheme(.light)
    }
}

struct ContentView_Previews_2: PreviewProvider {
    static var previews: some View {
        /*@START_MENU_TOKEN@*/Text("Hello, World!")/*@END_MENU_TOKEN@*/
    }
}

4

2 回答 2

1

您不能在(以及其他,例如)id中的视图有重复的 s 。由于您有重复的表情符号并且您通过 标识每个表情符号,因此您的视图具有重复的ID。LazyVGridListCardView\.self

解决方案#1(更糟)

仅当您有恒定数据时才使用它,否则您可能会遇到下面提到的问题。

使用索引。这将永远是独一无二的。但是,这可能会在emojis更改时引起问题,因为视图将交换 ID(这会破坏动画等)。这里的ids不是恒定的。

请参阅解决方案#2以获得更好的方法。

ForEach(0 ..< emojiCount, id: \.self) { emojiIndex in
    CardView(content: emojis[emojiIndex])
}

解决方案#2(更好)

您可以在常量或变异数据上使用它。

使每个表情符号唯一可识别。这是最好的解决方案。这里的ids常数。

struct MyEmoji: Identifiable {
    let id = UUID()
    let string: String

    init(_ string: String) {
        self.string = string
    }
}
var emojis: [MyEmoji] = [MyEmoji(""), MyEmoji(""), MyEmoji(""), MyEmoji(""),
                         MyEmoji(""), MyEmoji(""), MyEmoji(""), MyEmoji(""),
                         MyEmoji(""), MyEmoji(""), MyEmoji(""), MyEmoji(""),
                         MyEmoji(""), MyEmoji(""), MyEmoji(""), MyEmoji(""),
                         MyEmoji(""), MyEmoji(""), MyEmoji(""), MyEmoji(""),
                         MyEmoji(""), MyEmoji(""), MyEmoji(""), MyEmoji("")]
ForEach(emojis[0 ..< emojiCount]) { emoji in
    CardView(content: emoji.string)
}
于 2021-09-01T19:21:12.163 回答
0

您没有说如何使用索引,但以下在我自己的测试中有效:

ForEach(Array((emojis[0..<emojiCount]).enumerated()),id:\.offset) { index,emoji in {
  ....
}

我不确定 HStack 为什么会起作用,但总的来说,SwiftUI 使用 id 来跟踪更改,因此最好让它们尽可能接近真实标识符。在您使用 \.self 的情况下,它使用以重复 ID 结尾的表情符号字符串本身。今年(2021 年)有一个 WWDC 视频解释了 id 的重要性以及滥用如何导致奇怪的 SwiftUI 行为: https ://developer.apple.com/videos/play/wwdc2021/10022/

于 2021-09-01T19:33:11.950 回答