Having Trouble passing a ButtonStyle as a parameter to a func

I have a SwiftUI View where the body looks like this

             VStack {
                  VStack(spacing: 4) {
                    Text("Outline")
                    Button("Tap Me") {
                      print("tapped")
                    }
                    .buttonStyle(.outline)
                  }
                  VStack(spacing: 4) {
                    Text("Simple")
                    Button("Tap Me") {
                      print("tapped")
                    }
                    .buttonStyle(.simple)
                  }
                }

So to remove the duplication, I want to do something like this:

     func textButton(title: String, buttonStyle: ButtonStyle) -> some View {
      VStack {
        Text(title)
        Button("hello") {
          print("tapped")
        }
          .buttonStyle(buttonStyle)
      }
    }

The compiler asks me to add 'any' before ButtonStyle. When I do that I get the following: "Type 'any View' cannot conform to 'View'" It works fine if I don't pass in the ButtonStyle. Any suggestions on how to pass a ButtonStyle into a func? thanks, in advance!

Answered by DTS Engineer in 739921022

It should work if you declare your function like this:

    func textButton(title: String, buttonStyle: some PrimitiveButtonStyle) -> some View {
      VStack {
        Text(title)
        Button("hello") {
          print("tapped")
        }
          .buttonStyle(buttonStyle)
      }
    }

The reason is that the various button styles are different type (rather than, for example, all being cases of a single enum), connected via "existential" conformance to the ButtonStyle protocol. The some keyword "opens the existential", which is another way of saying that it accepts any of the possible types.

Accepted Answer

It should work if you declare your function like this:

    func textButton(title: String, buttonStyle: some PrimitiveButtonStyle) -> some View {
      VStack {
        Text(title)
        Button("hello") {
          print("tapped")
        }
          .buttonStyle(buttonStyle)
      }
    }

The reason is that the various button styles are different type (rather than, for example, all being cases of a single enum), connected via "existential" conformance to the ButtonStyle protocol. The some keyword "opens the existential", which is another way of saying that it accepts any of the possible types.

I'm trying to create a custom button where I can pass in a style. I have figured out how to pass a ButtonStyle as a parameter using a generic, but after that I can't do anything with it:

struct SelectableButton: View
{
	@Environment(\.isEnabled) private var isEnabled

	var text: String = ""
	var icon: Image?
	var onClick: (() -> Void)
	var selected: Bool = false
	var style: Any

	init<S: ButtonStyle>(label: String, icon: Image? = nil, onClick: @escaping (() -> Void), style: S)
	{
		text = label
		self.icon = icon
		self.onClick = onClick
		self.style = style
	}

	var body: some View
	{
		Button(action: onClick)
		{
			HStack
			{
				Text(text)
				icon
			}
		}
		.buttonStyle(self.style as! ButtonStyle)  // DOES NOT WORK. "No exact matches"
	}
}
Having Trouble passing a ButtonStyle as a parameter to a func
 
 
Q