I'm making a simple minesweeper app. At the bottom I have a toolbar with a button to toggle whether the game is in "flagging mode". I have two possible images for the button itself- one for when flagging mode is enabled and another for when it isn't- and I'd like it to switch between the two when it's clicked.
Essentially, I want to make a toggle with custom images for on/off.
However, the code I have below isn't updating the image and I can't figure out why.
GameView() // the content view
.environmentObject(game)
.padding()
.toolbar {
ToolbarItemGroup(placement: .bottomBar) {
Button(action: game.toggleFlagMode) {
if game.isFlagMode {
Image("flag toggle on")
.resizable()
.aspectRatio(contentMode: .fit)
}
else {
Image("flag toggle off")
.resizable()
.aspectRatio(contentMode: .fit)
}
}
Button("Reset") {
game.resetBoard()
}
}
}
And my Game.swift file (shortened to what's relevant)
import Foundation
class Game: ObservableObject {
@Published var isFlagMode: Bool
[ ... ]
init(from settings: GameSettings) {
self.isFlagMode = false
[ ... ]
}
// toggle whether the game is in mode to flag cells
func toggleFlagMode() {
self.isFlagMode = !self.isFlagMode
}
Flag mode is correctly being toggled by the button. That is- when I click it to enable it's properly flagging cells when clicked. So I think the issue is with the View and not Game itself.
EDIT (Solution):
I had this code in my main MinesweeperApp.swift file. I placed the toolbar code into a different view that MinesweeperApp was calling and it started working.
CodePudding user response:
A couple of mistake you have:
In the viewModel you could just:
func toggleFlagMode() {
self.isFlagMode.toggle()
}
In the view:
.environmentObject(game)
.padding()
.toolbar {
ToolbarItemGroup(placement: .bottomBar) {
Button(action: game.toggleFlagMode) {
Image(systemName: game.isFlagMode ? "square.and.arrow.up" : "pencil")
.resizable()
.aspectRatio(contentMode: .fit)
.foregroundColor(.red)
}
Button("Reset") {
game.resetBoard()
}
}
}
If you are using imported images(from Assets) remember to remove the systemName.
CodePudding user response:
The simplest way to handle this is with an @State variable. In other words it's a variable that updates the view when the state changes. For example.
@State var isFlaggingModeEnabled = false
var body: some View {
Button(action: { isFlaggingModeEnabled.toggle() },
label: {
switch isFlaggingModeEnabled {
case true:
// Your image for when enabled.
default:
// Your image for when disabled.
}
}
}
CodePudding user response:
GameView() // the content view
.environmentObject(game)
.padding()
.toolbar {
ToolbarItemGroup(placement: .bottomBar) {
Button(action: {
game.toggleFlagMode()
}) {
Image(game.isFlagMode ? "poire" : "pomme")
.resizable()
.aspectRatio(contentMode: .fit)
}
Button("Reset") {
game.resetBoard()
}
}
}

