Alternating Button Styling Help

Hello! Need help with some styling of a couple of buttons.

What I’m trying to achieve is to have the two buttons: “Product” and “Supplies” be selected and deselected when one is pressed (i.e. when Product is pressed it will turn blue and the Supply button will turn gray, vice versa).

Also, it would be a GREAT help if someone could point me in the direction of getting a basic filter function going, so if anyone can point me in the direction of a knowledge-base for that, I would be very grateful! Thank you!

GitHub Link:

Your GitHub repo is not a useable project since it is missing a lot of files.

Sample code of two buttons where the color changes depending on which one has been tapped. There’s probably a number of ways of doing this but this is one way.

struct ContentView: View {
    @State private var isProductSelected = true


    var body: some View {
        HStack {
            Button(action: {
                isProductSelected = true
            }, label: {
                Text("Product")
            })
            .tint(isProductSelected ? .blue : .gray)
            .padding()

            Button(action: {
                isProductSelected = false
            }, label: {
                Text("Supplies")
            })
            .tint(isProductSelected ? .gray : .blue)
            .padding()

        }
        .padding(.horizontal)
    }
}

As far as a filter is concerned, what is the data structure that you are using and what do you want to filter on?

Thanks for the insight Chris. I’ve updated my code to show all of the data, sorry about the inconvenience.

I’ll try the code for the alternating buttons.

For the filter, I am wanting to filter on information that is contained within DataService in order to filter out “Salsa Jar” or even “9 oz”, “Salsa Jar”. I only have three data points at the moment, but I’ll be adding more at some point.

Looking at the struct you have and the sample data in DataService, if we take the first one which is
InventoryItem(image: "9ozSalsa", type: "Salsa Jar", size: 9, scent: "Lemon Cedar", stock: 3),

and where you say:

you don’t have anything searchable which is “9 oz”. “Salsa Jar” is fine and so is “9” although that field is an Int but you don’t have “oz”.
What I am getting at is that if you are wanting to search different fields with different data types then the search filter is going to be very complex.

Realistically, the way to think about searching is what a user might do when entering text in a search field and then you have to think about how to use that search string.

For example, if the user types in “9 oz Salsa Jar”, do you break it up into an array of words like this: [“9”, “oz”, “Salsa”, “Jar”] which you can do by saying
let searchArray = searchText.components(separatedBy: " ")
The filter process could be configured to scan through the entire list of products looking for any instance where the type or size or scent matches any of those array entries. To be honest I am not sure how to structure that just now but I’ll think about it.

Thanks Chris! I’ll try switching the Int to a String.

Going back to the buttons, I don’t know why, but it’s only turning blue and gray the selected buttons, the other button in the view does not refresh to the new color based on the selection of the button (i.e. Product button turns gray when Supplies button is pressed). I did reduce my code, because I figured I didn’t need a var for each button, just run it off the productButtonSelected var.

Am I missing something that would cause the view to refresh the Product or Supplies button once the view is refreshed?

I think your Products and Supplies buttons are perhaps overly complicated and could be done more simply with the action in-line while using a CustomView for just the Button label. For example, your Custom Button could be like this:

struct CustomButton: View {
    var productButtonSelected: Bool
    var buttonText: String
    
    var body: some View {
        Text(buttonText)
            .frame(width: 150, height: 50)
            .background(productButtonSelected ? .blue.opacity(0.45) : .gray.opacity(0.45))
            .cornerRadius(10)
            .foregroundColor(.white)
            .font(.headline)
        //  Optional overlay to create a slightly darker edge around the button
            .overlay(
                RoundedRectangle(cornerRadius: 10)
                    .stroke(productButtonSelected ? Color.blue.opacity(0.5) : Color.gray.opacity(0.5), lineWidth: 2)
            )
    }
}

#Preview {
    CustomButton(productButtonSelected: true, buttonText: "Products")
}

The overlay gets around the issue that .border() places a square around the edge of the button and when you set the cornerRadius to 10, those corners are cut off. The overlay draws a smooth corner that follows the existing contour since the stroke radius is the same as the corner radius.
Setting the stroke lineWidth to 2 makes it a little more prominent.

You could use the same technique for your Dash Buttons.

and in your Inventory View you could so this:

HStack {
    Button(action: {
        productButtonSelected = true
    }, label: {
        CustomButton(productButtonSelected: productButtonSelected, buttonText: "Products")
    })

    Button(action: {
        productButtonSelected = false
    }, label: {
        CustomButton(productButtonSelected: !productButtonSelected, buttonText: "Supplies")
    })
}

Once again, Chris, you’ve saved me! Got them to work! I appreciate your help!