使用 ObservedObject 而不是我的自定义视图更新文本
Text updating with ObservedObject but not my custom View
我正在尝试将棋盘游戏 Splendor 编码为 SwiftUI 中的一个简单编码项目。我有点像 hack,所以如果我弄错了,请指出正确的方向。我也在尝试使用 MVVM 范例。
游戏板上有两叠代币,一叠用于无人认领的游戏代币,另一叠用于当前玩家的代币。棋盘上有一个按钮,允许玩家一次领取一个令牌。
令牌是在自定义视图中绘制的 - TokenView() - 它绘制了一个简单的 Circle() 偏移量较小以形成堆栈。圆圈的数量与令牌的数量相匹配。在每堆令牌下面是一个 Text(),它打印令牌的数量。
按下按钮时,只有 Text() 正确更新,绘制的标记数保持不变。
我知道我的问题与我混合@ObservedObject 和静态 Int 这一事实有关。我不知道如何不使用 Int,因为 TokenView 不知道它是在绘制棋盘的令牌集合还是活跃玩家的令牌集合。如何将令牌计数作为@ObservedObject 传递?为什么 Text() 会正确更新?
型号:
struct TheGame {
var tokenCollection: TokenCollection
var players: [Player]
init() {
self.tokenCollection = TokenCollection()
self.players = [Player()]
}
}
struct Player {
var tokenCollection: TokenCollection
init() {
self.tokenCollection = TokenCollection()
}
}
struct TokenCollection {
var count: Int
init() {
self.count = 5
}
}
视图模型:
class MyGame: ObservableObject {
@Published private (set) var theGame = TheGame()
func collectToken() {
theGame.tokenCollection.count -= 1
theGame.players[0].tokenCollection.count += 1
}
}
游戏板视图:
struct GameBoardView: View {
@StateObject var myGame = MyGame()
var body: some View {
VStack{
TokenStackView(myGame: myGame, tokenCount: myGame.theGame.tokenCollection.count)
.frame(width: 100, height: 200, alignment: .center)
Button {
myGame.collectToken()
} label: {
Text ("Collect Token")
}
TokenStackView(myGame: myGame, tokenCount: myGame.theGame.players[0].tokenCollection.count) .frame(width: 100, height: 200, alignment: .center)
}
}
}
TokenStackView:
struct TokenStackView: View {
@ObservedObject var myGame: MyGame
var tokenCount: Int
var body: some View {
VStack {
ZStack {
ForEach (0..<tokenCount) { index in
Circle()
.stroke(lineWidth: 5)
.offset(x: CGFloat(index * 10), y: CGFloat(index * 10))
}
}
Spacer()
Text("\(tokenCount)")
}
}
}
如果您查看控制台,您会看到以下错误:
ForEach<Range<Int>, Int, OffsetShape<_StrokedShape<Circle>>> count (2) != its initial count (1). `ForEach(_:content:)` should only be used for *constant* data. Instead conform data to `Identifiable` or use `ForEach(_:id:content:)` and provide an explicit `id`!
在这种情况下修复非常简单,只需添加 id
,如下所示:
ForEach(0..<tokenCount, id: \.self) {
我正在尝试将棋盘游戏 Splendor 编码为 SwiftUI 中的一个简单编码项目。我有点像 hack,所以如果我弄错了,请指出正确的方向。我也在尝试使用 MVVM 范例。
游戏板上有两叠代币,一叠用于无人认领的游戏代币,另一叠用于当前玩家的代币。棋盘上有一个按钮,允许玩家一次领取一个令牌。
令牌是在自定义视图中绘制的 - TokenView() - 它绘制了一个简单的 Circle() 偏移量较小以形成堆栈。圆圈的数量与令牌的数量相匹配。在每堆令牌下面是一个 Text(),它打印令牌的数量。
按下按钮时,只有 Text() 正确更新,绘制的标记数保持不变。
我知道我的问题与我混合@ObservedObject 和静态 Int 这一事实有关。我不知道如何不使用 Int,因为 TokenView 不知道它是在绘制棋盘的令牌集合还是活跃玩家的令牌集合。如何将令牌计数作为@ObservedObject 传递?为什么 Text() 会正确更新?
型号:
struct TheGame {
var tokenCollection: TokenCollection
var players: [Player]
init() {
self.tokenCollection = TokenCollection()
self.players = [Player()]
}
}
struct Player {
var tokenCollection: TokenCollection
init() {
self.tokenCollection = TokenCollection()
}
}
struct TokenCollection {
var count: Int
init() {
self.count = 5
}
}
视图模型:
class MyGame: ObservableObject {
@Published private (set) var theGame = TheGame()
func collectToken() {
theGame.tokenCollection.count -= 1
theGame.players[0].tokenCollection.count += 1
}
}
游戏板视图:
struct GameBoardView: View {
@StateObject var myGame = MyGame()
var body: some View {
VStack{
TokenStackView(myGame: myGame, tokenCount: myGame.theGame.tokenCollection.count)
.frame(width: 100, height: 200, alignment: .center)
Button {
myGame.collectToken()
} label: {
Text ("Collect Token")
}
TokenStackView(myGame: myGame, tokenCount: myGame.theGame.players[0].tokenCollection.count) .frame(width: 100, height: 200, alignment: .center)
}
}
}
TokenStackView:
struct TokenStackView: View {
@ObservedObject var myGame: MyGame
var tokenCount: Int
var body: some View {
VStack {
ZStack {
ForEach (0..<tokenCount) { index in
Circle()
.stroke(lineWidth: 5)
.offset(x: CGFloat(index * 10), y: CGFloat(index * 10))
}
}
Spacer()
Text("\(tokenCount)")
}
}
}
如果您查看控制台,您会看到以下错误:
ForEach<Range<Int>, Int, OffsetShape<_StrokedShape<Circle>>> count (2) != its initial count (1). `ForEach(_:content:)` should only be used for *constant* data. Instead conform data to `Identifiable` or use `ForEach(_:id:content:)` and provide an explicit `id`!
在这种情况下修复非常简单,只需添加 id
,如下所示:
ForEach(0..<tokenCount, id: \.self) {