'Trying to create a grid of numbers that must be clicked in order and when clicked the background changes color SWIFTUI

As the title says I am trying to create a grid of random numbers that must be clicked in ascending order and when pressed the background changes color so they're no longer visible.

I figured out how to create the grid from 0 to what ever size grid I want (5x5, 10x10, etc...)

I want the background to be white to start and then when the button is pressed it changes to black

The two biggest issues I'm having are all of the buttons turning black after I press on one button and the numbers randomize every time I press a button.

Any one have any ideas?

import SwiftUI

struct ContentView: View {
@State var buttonbackg = Color.white
@State var gridsize = 100
var body: some View {
    
    //make grid
    let cellCount = (gridsize/10)
    let r = numbrand(min: 00, max: ((gridsize/10) * (gridsize/10) - 1))
   
    ZStack{
        Rectangle()
            .ignoresSafeArea()
            .background(Color.black)
        VStack{
            Text("Concentration Grid")
                .font(.title)
            .foregroundColor(Color.white)
            .multilineTextAlignment(.center)
            .padding(.bottom)
            
            Spacer()
        }
        VStack(spacing:3) {
            
            
            Spacer()
          
               ForEach(1...cellCount, id:\.self) { i in
               
               HStack(spacing:3) {
                   Spacer()
                   ForEach(1...cellCount, id:\.self) { c in
                       
                       let a = r()
                       
                       ZStack {
                          
                          
                           
                           Button(action:{
                               if (self.buttonbackg == .white) {
                                  self.buttonbackg = .black
                                }
                           }){
                           
                           
                               Text("\(a)")
                               
                               .foregroundColor(Color.black)
                               .frame(width: 28, height: 28)
                               .background(buttonbackg)
                               .cornerRadius(5)
                               .multilineTextAlignment(.center)
                               .scaledToFit()
                               .padding(.all, -2)
                               Spacer()
                                   
                               }
                           Spacer()
                       }
                       
                       
                      }
                   
                  }
                   Spacer()
             }
            Spacer()
          }
    }
      }
    //^grid



func numbrand(min: Int, max:Int) -> () -> Int{
    //let array: [Int] = Array(min...max)
    var numbers: [Int] = []
    return {
        if numbers.isEmpty {
            numbers = Array(min...max)
        }
        
        let index = Int(arc4random_uniform(UInt32(numbers.count)))
        return numbers.remove(at: index)
    }
    
}
}

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


Solution 1:[1]

Every-time you click a button, view redraws itself and thus your randomArray is created again

You need to create a Struct here which holds the property whether the button is selected or not.

Give it a try this way:

struct concentrationGame: Hashable {
    var id = UUID()
    var number: Int = 0
    var isSelected: Bool = false
}

class RandomNumbers: ObservableObject {
    @Published var randomNumbers : [concentrationGame]
    
    init() {
        self.randomNumbers = (1...100).map{_ in arc4random_uniform(100)}.map({ concentrationGame(number: Int($0)) })
    }
}

struct ContentView: View {
    
    @ObservedObject var randomNumbers = RandomNumbers()
    private var gridItemLayout = [GridItem(.adaptive(minimum: 50))]
    
    var body: some View {
        NavigationView {
            ScrollView {
                LazyVGrid(columns: gridItemLayout, spacing: 20) {
                    ForEach($randomNumbers.randomNumbers, id: \.self) { $randomNumbers in
                        Button(String(randomNumbers.number)) { randomNumbers.isSelected.toggle() }
                                .frame(minWidth: 0, maxWidth: .infinity, minHeight: 50)
                                .foregroundColor(.white)
                                .background( randomNumbers.isSelected ? .white : .black)
                            .cornerRadius(10)
                    }
                }
            }
            .padding()
            .ignoresSafeArea(edges: .bottom)
            .navigationTitle("Concentration Grid")
            .navigationBarTitleDisplayMode(.inline)
        }
    }
}

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

enter image description here

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1