G. Marc
G. Marc

Reputation: 6037

Button is not selectable on tvOS using own ButtonStyle in SwiftUI

After replacing a standard button style with a custom one, the button isn't selectable anymore on tvOS (it works as expected on iOS). Is there a special modifier in PlainButtonStyle() that I'm missing? Or is it a bug in SwiftUI?

Here's the snipped that works:

Button(
    action: { },
    label: { Text("Start") }
).buttonStyle(PlainButtonStyle())

and here's the one that doesn't:

Button(
    action: { },
    label: { Text("Start") }
).buttonStyle(RoundedButtonStyle())

where RoundedButtonStyle() is defined as:

struct RoundedButtonStyle: ButtonStyle {
    func makeBody(configuration: Configuration) -> some View {
        configuration.label
            .padding(6)
            .foregroundColor(Color.white)
            .background(Color.blue)
            .cornerRadius(100)
    }
}

Upvotes: 7

Views: 3606

Answers (2)

Abedalkareem Omreyh
Abedalkareem Omreyh

Reputation: 2329

I have done it in this way and it's working fine, what you need to do is just handling the focused state.

struct AppButtonStyle: ButtonStyle {
  
  let color: Color = .clear

  func makeBody(configuration: Configuration) -> some View {
    return AppButton(configuration: configuration, color: color)
  }
  
  
  struct AppButton: View {
    @State var focused: Bool = false

    let configuration: ButtonStyle.Configuration
    let color: Color
    
    var body: some View {
      configuration.label
        .foregroundColor(.white)
        .background(RoundedRectangle(cornerRadius: 20).fill(color))
        .compositingGroup()
        .shadow(color: .black, radius: 5)
        .scaleEffect(focused ? 1.1 : 1.0)
        .padding()
        .focusable(true) { focused in
          withAnimation {
            self.focused = focused
          }
        }
    }
  }
}

When the button is getting focused I'm just scaling it and you can do something else as you wish with the same idea, so let's say you wan't to change the background color:

.background(RoundedRectangle(cornerRadius: 20).fill(focused ? .red : .white))

To use:

struct SomeView: View {
  var body: some View {
    NavigationView {
      NavigationLink(
        destination: Text("Destination")) {
        Text("Hi")
      }
      .buttonStyle(AppButtonStyle())
      .padding()
    }
  }
}

Upvotes: 2

Marc T.
Marc T.

Reputation: 5340

If you create your own style you have to handle focus manual. Of course there are different ways how you could do this.

struct RoundedButtonStyle: ButtonStyle {

    let focused: Bool
    func makeBody(configuration: Configuration) -> some View {
        configuration
            .label
            .padding(6)
            .foregroundColor(Color.white)
            .background(Color.blue)
            .cornerRadius(100)
            .shadow(color: .black, radius: self.focused ? 20 : 0, x: 0, y: 0) //  0

    }
}
struct ContentView: View {

    @State private var buttonFocus: Bool = false
    var body: some View {
        VStack {
            Text("Hello World")

            Button(
                action: { },
                label: { Text("Start") }
            ).buttonStyle(RoundedButtonStyle(focused: buttonFocus))
                .focusable(true) { (value) in
                    self.buttonFocus = value
            }
        }
    }
}

Upvotes: 2

Related Questions