使用ForEach创建视图,但是如何使onTapGesture立即更新?

时间:2020-10-18 17:32:37

标签: swiftui

此代码的工作方式与我想要的随机播放动画完全相同,不同之处在于,当用户点按一个矩形(在随机播放之间)时,onTapGesture中的颜色更改直到下一次随机播放时才更新。轻按时我需要查看颜色变化。 我尝试了几种不同的方法来完成此操作,每种方法对我来说都是死路一条。是我的数据模型偏离了轨道吗?有没有更好的方法可以做到这一点? 提前致谢!我对SwiftUI还是很陌生,所以期待从中学到东西。

import SwiftUI

class EachSpace: ObservableObject, Identifiable {
    
    let id = UUID()
    @Published var num: Int
    @Published var tapped: Bool
    @Published var highlight: Bool
    
    init(number: Int) {
        num = number
        tapped = false
        highlight = false
    }
    
}

class Column: ObservableObject, Identifiable {
    
    @Published var spaces = [EachSpace]()
    @Published var space0: EachSpace
    @Published var space1: EachSpace
    @Published var space2: EachSpace
    @Published var space3: EachSpace
    @Published var space4: EachSpace
    let id = UUID()
    
    init(low: Int, high: Int) {
        var randIntArray = [Int]()
        var tempNum = 0
        var found = false
        for _ in 0..<5 {
            repeat {
                tempNum = Int.random(in: low...high)
                if (randIntArray.firstIndex(where: {$0 == tempNum}) != nil) {
                    found = true
                } else { found = false }
            } while found
            randIntArray.append(tempNum)
        }
        space0 = EachSpace(number: randIntArray[0])
        space1 = EachSpace(number: randIntArray[1])
        space2 = EachSpace(number: randIntArray[2])
        space3 = EachSpace(number: randIntArray[3])
        space4 = EachSpace(number: randIntArray[4])

        spaces.append(space0)
        spaces.append(space1)
        spaces.append(space2)
        spaces.append(space3)
        spaces.append(space4)

    }
}

class Card: ObservableObject {

    @Published var columns = [Column]()
    @Published var columnX = Column(low: 1, high: 25)
    @Published var columnY = Column(low: 26, high: 50)
    @Published var columnZ = Column(low: 51, high: 75)
    
    init() {
        columns.append(columnX)
        columns.append(columnY)
        columns.append(columnZ)
    }
    
}

struct ContentView: View {

    @State private var rotate = false
    @ObservedObject var card = Card()
    
    var body: some View {

        VStack {
            
            HStack {
                ForEach(card.columns) { col in
                    VStack {
                        ForEach(col.spaces) { space in
                            Text("\(String(space.num))")
                                .font(.system(size: 20))
                                .fontWeight(.black)
                                .frame(width: 40, height: 40, alignment: .center)
                                .background(space.tapped ? Color.blue : Color.red)
                                .clipShape(Rectangle())
                                .foregroundColor(.white)
                                .padding(10)
                                .rotationEffect(Angle(degrees: rotate ? 0 : 360))
                                .onTapGesture {
                                    space.tapped.toggle()
                                }
                        }
                    }
                }
            }
            Button(action: {
                withAnimation(Animation.linear(duration: 1.0)) {
                    self.rotate.toggle()
                    self.card.columnX.spaces.shuffle()
                    self.card.columnY.spaces.shuffle()
                    self.card.columnZ.spaces.shuffle()
                }
            })
            {
                Text("Shuffle")
            }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

1 个答案:

答案 0 :(得分:1)

原因是@ObservedObject / ObservableObject没有跨越嵌套的可观察对象-即观察根{{1}的视图未观察到EachSpace.tapped的变化}对象。

最简单的解决方法是将最里面的Card视图移动到一个单独的视图中,该视图将直接观察每个Text对象:

EachSpace

并将struct SpaceView: View { @ObservedObject var space: EachSpace var body: some View { Text("\(String(space.num))") .font(.system(size: 20)) .fontWeight(.black) .frame(width: 40, height: 40, alignment: .center) .background(space.tapped ? Color.blue : Color.red) .clipShape(Rectangle()) .foregroundColor(.white) .padding(10) .rotationEffect(Angle(degrees: rotate ? 0 : 360)) .onTapGesture { space.tapped.toggle() } } } 中的ForEach更改为:

ContentView