Kedar
Kedar

Reputation: 35

How can I make these SwiftUI text "buttons" change color on tap?

In SwiftUI, how can I make these text "buttons" change color on tap, but revert when you remove your finger?

https://i.sstatic.net/1R0OJ.jpg

Here's what the button code looks like:

    LazyVGrid(columns:
                Array(repeating:
                GridItem(.flexible(),
                spacing: 5),
                count: 2),
                spacing: 2) {
        
        ForEach(viewModel.productIngredients, id: \.self) { ingredient in
            
           Text(ingredient.name)
                .font(.system(size: 14))
                .fontWeight(.medium)
                .foregroundColor(.black)
                .padding(8)
                .background(RoundedRectangle(cornerRadius: 10).stroke(Color.black, lineWidth: 2))
                .padding(.top,5)
///             .background(self.selectedIngredient == ingredient ? Color.blue : Color.white)
                .onTapGesture {
                    self.didTap.toggle()
                    self.selectedIngredient = ingredient
                }
            }
    }

Upvotes: 2

Views: 9358

Answers (2)

I found a slightly simpler way to change the color of a button in SwiftUI

Button(
    action: {
            print("¡Hola, mundo!")
            }
      )
        {
          Text("¡Hola, mundo!")
          .foregroundColor(.blue)
         }

Upvotes: 0

jnpdx
jnpdx

Reputation: 52565

You can use a custom ButtonStyle to do this:

struct ContentView : View {
    var body: some View {
        Button(action: {
            //Your action code, taken from the previous `onTapGesture` in the original code
            //didTap.toggle()
            //selectedIngredient = ingredient
        }) {
            Text("Ingredient")
                .fontWeight(.medium)
        }.buttonStyle(CustomButtonStyle(isSelected: false)) //could pass a parameter here like isSelected: selectedIngredient == ingredient from your original code
    }
}

struct CustomButtonStyle : ButtonStyle {
    var isSelected: Bool
 
    func makeBody(configuration: Configuration) -> some View {
        configuration.label
            .font(.system(size: 14))
            .foregroundColor(.black)
            .padding(8)
            .background(RoundedRectangle(cornerRadius: 10)
                            .stroke(configuration.isPressed ? Color.red : Color.black, lineWidth: 2)
            )
            .padding(.top,5)
            //Could also modify style based on isSelected
    }
}

Notice that your Text view is now wrapped in a Button and given a buttonStyle of CustomButtonStyle.

Inside CustomButtonStyle, I use a ternary expression to set the color of the background RoundedRectangle based on configuration.isPressed.

I also showed how you could pass in another parameter (isSelected) because in your original example it looked like you may want to do things conditionally based on that as well.


Update with full working example showing columns:
struct Ingredient : Identifiable, Hashable {
    var id = UUID()
    var name = "Ingredient"
}

struct ContentView: View {
    
    @State var ingredients = [Ingredient(),Ingredient(),Ingredient(),Ingredient(),Ingredient(),Ingredient(),Ingredient(),Ingredient()]
    
    var body: some View {
        LazyVGrid(columns:
                    Array(repeating:
                            GridItem(.flexible(),
                                     spacing: 5),
                          count: 2),
                  spacing: 2) {
            
            ForEach(ingredients, id: \.self) { ingredient in
                
                Button(action: {
                    //Your action code, taken from the previous `onTapGesture` in the original code
                    //didTap.toggle()
                    //selectedIngredient = ingredient
                }) {
                    Text(ingredient.name)
                        .fontWeight(.medium)
                }.buttonStyle(CustomButtonStyle(isSelected: false))
            }
        }
    }
}

struct CustomButtonStyle : ButtonStyle {
    var isSelected: Bool
    
    func makeBody(configuration: Configuration) -> some View {
        configuration.label
            .font(.system(size: 14))
            .foregroundColor(.black)
            .padding(8)
            .background(RoundedRectangle(cornerRadius: 10)
                            .stroke(configuration.isPressed ? Color.red : Color.black, lineWidth: 2)
            )
            .padding(.top,5)
        //Could also modify style based on isSelected
    }
}

Upvotes: 5

Related Questions