Symphonic eMotions
Symphonic eMotions

Reputation: 37

SwiftUI onTapGesture not working when @State is passed to function

This View is drawing a grid based on a number of rows and columns. Say you have 2 rows and 2 colums you and up with 4 cells. Each cell has an .onTapGesture which I like to use to change the cell color when clicked on.

I learned that I need to use a @State var to keep track of changes (colors in this case) so redrawing will be automatic. But as soon as I pass the @State var to the method for returning the new color, the onTapGesture is not called at all. Why is that?

This is the View:

struct EditGridView: View {
    
    @ObservedObject var playViewModel: PlayViewModel
    
    @State var cellColors: [Color]
    
    var body: some View {
        VStack {
            
            ForEach(0..<playViewModel.playViewState.currentInstrumentsSet.rows, id: \.self) { row in
                HStack {
                    ForEach(0..<playViewModel.playViewState.currentInstrumentsSet.columns, id: \.self) { column in
                        ZStack {
                            RoundedRectangle(cornerRadius: 7.0)
                            .fill(
                                playViewModel.partColor(
                                    row: row,
                                    column: column,
                                    cellColors: cellColors
                                )
                            )
                            .overlay(RoundedRectangle(cornerRadius: 7.0).stroke(Color("GridBorderColor")))
                            .cornerRadius(7.0)
                        }


                        .onTapGesture {
                            cellColors = playViewModel.tapOnCell(
                                index: InstrumentsSet.Track.Part.Index(row: row, column: column),
                                currentCellColors: cellColors
                            )
                        }
                    }
                }
            }
        }.aspectRatio(1.77777, contentMode: .fit)
    }
}

This is the method called, which does nothing yet but showing the current color:

public func partColor(row: Int, column: Int, cellColors: [Color]) -> Color {
        
        let index: Int = row * setSettings.gridColumns + column
        
        let color = cellColors[index]
        
        print("color \(color) at index: \(index)")
        
        return color
    }

When I leave out the @State var cellColors the function partColor is called just fine. But I need to use this state var to redraw the new colors when changed? What trivial thing do I miss?

Upvotes: 1

Views: 236

Answers (1)

stosha
stosha

Reputation: 2148

Try like this (hopefully the idea is clear):

 struct EditGridView: View {
    @ObservedObject var playViewModel: PlayViewModel
    
    var body: some View {
        VStack {
            ...
            .fill(
                playViewModel.partColor(row: row, column: column)
                ...
                    .onTapGesture {
                       playViewModel.tapOnCell(index: 0)
                    }
                ...
    }
 } 

 class PlayViewModel: ObservableObject {

    @Published var cellColors: [Color] = [.red, .blue, .orange, .green]

    func partColor(row: Int, column: Int) -> Color {
        return cellColors[row + column]
    }
    
    func tapOnCell(index: Int) {
        cellColors = [.green, .red, .blue, .orange]
    }
 }

Upvotes: 2

Related Questions