Roshan  Chamlagain
Roshan Chamlagain

Reputation: 305

How to change background of buttons with different color when clicking the buttons inside forEach statement in SwiftUI?

I want to color the buttons as colors array above. For eg: if a user first selects any button then the color of that button should be orange, and if the user selects another button then it should be green and so on. The user can select upto 7 buttons from the total of 10 buttons and if 7 different buttons are selected, then they should have 7 different color.

import SwiftUI

struct ColorModel: Identifiable {
    let value: Color
    let id = UUID()
}
let colors = [
    ColorModel(value: Color.orange),
    ColorModel(value: Color.green),
    ColorModel(value: Color.blue),
    ColorModel(value: Color.red),
    ColorModel(value: Color.yellow),
    ColorModel(value: Color.gray),
    ColorModel(value: Color.pink),
]
let totalButtons: Int = 10

struct ContentView: View {
    @State private var selectedButtons = [Int]()

    var body: some View {
        ForEach(0..<totalButtons) { index in
            Button(action: {
                self.updateSelectButton(value: index)
            }) {
                Text("Button \(index)")
            }
            .background(self.selectedButtons.contains(index) ? colors[index].value : Color.white)
        }
    }

    func updateSelectButton(value: Int) {
        guard value < colors.count else {
            return
        }
        if let index = self.selectedButtons.firstIndex(of: value) {
            self.selectedButtons.remove(at: index)
        } else {
            self.selectedButtons.append(value)
        }
    }
}

The code looks like above. The problem with above code is that user can't select the 8th, 9th and 10th buttons in the array. User can only select first 7 buttons.

Upvotes: 0

Views: 723

Answers (2)

pawello2222
pawello2222

Reputation: 54621

You may try the following:

struct ContentView: View {
    @State private var selectedButtons = [Int]()

    var body: some View {
        ForEach(0 ..< totalButtons) { index in
            Button(action: {
                self.updateSelectButton(value: index)
            }) {
                Text("Button \(index)")
            }
            .background(self.buttonColor(value: index)) // <- extract to another function for clarity
        }
    }

    func updateSelectButton(value: Int) {
        if let index = selectedButtons.firstIndex(of: value) {
            selectedButtons.remove(at: index)
        } else if selectedButtons.count < 7 { // <- make sure we never go above 7
            selectedButtons.append(value)
        }
    }
    
    func buttonColor(value: Int) -> Color {
        if let index = selectedButtons.firstIndex(of: value), index < colors.count { // <- safety check
            return colors[index].value
        } else {
            return .white
        }
    }
}

This solution will keep the order in which you add buttons. Which means if you remove the first button you added (in orange colour) the second button will become first and will be recoloured form green to orange.

You may also want to extract the hardcoded value 7 and replace it with some variable.

Upvotes: 2

Chaman Sharma
Chaman Sharma

Reputation: 636

You need to remove this line of code. User can't select the 8th, 9th and 10th buttons in the array due to this line.

   guard value < colors.count else {
        return
    }

Use this code instead

    if self.selectedButtons.count >= 7 {
        return
    }

}

Upvotes: 0

Related Questions