Home > Mobile >  SwiftUI how to change a button/toggle image when clicked?
SwiftUI how to change a button/toggle image when clicked?

Time:01-19

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.

enter image description here

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()
        }
    }
}
  •  Tags:  
  • Related