Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SwiftUI: Custom button does not recognize touch with clear background and buttonStyle

I stumbled upon a weird behaviour for Buttons in SwiftUI in combination with a custom ButtonStyle.

My target was to create a custom ButtonStyle with some kind of 'push-back animation'. I used the following setup for this:

struct CustomButton<Content: View>: View {
    private let content: () -> Content

    init(content: @escaping () -> Content) {
        self.content = content
    }

    var body: some View {
        VStack {
            Button(action: { ... }) {
                content()
            }
            .buttonStyle(PushBackButtonStyle(pushBackScale: 0.9))
        }
    }
}

private struct PushBackButtonStyle: ButtonStyle {
    let pushBackScale: CGFloat

    func makeBody(configuration: Self.Configuration) -> some View {
        configuration
            .label
            .scaleEffect(configuration.isPressed ? pushBackScale : 1.0)
    }
}

// Preview
struct Playground_Previews: PreviewProvider {
    static var previews: some View {
        CustomButton {
            VStack(spacing: 10) {
                HStack {
                    Text("Button Text").background(Color.orange)
                }

                Divider()

                HStack {
                    Text("Detail Text").background(Color.orange)
                }
            }
        }
        .background(Color.red)
    }
}

When I now try to touch on this button outside of the Text view, nothing will happen. No animation will be visible and the action block will not be called.

showcase

What I found out so far:

  • when you remove the .buttonStyle(...) it does work as expected (no custom animation of course)
  • or when you set a .background(Color.red)) on the VStack in the CustomButton it does also work as expected in combination with the .buttonStyle(...)

The question now is if anybody have a better idea of how to properly work around this issue or how to fix it?

like image 860
Stone Avatar asked Jan 01 '23 03:01

Stone


1 Answers

Just add hit testing content shape in your custom button style, like below

Tested with Xcode 11.4 / iOS 13.4

demo

private struct PushBackButtonStyle: ButtonStyle {
    let pushBackScale: CGFloat

    func makeBody(configuration: Self.Configuration) -> some View {
        configuration
            .label
            .contentShape(Rectangle())     // << fix !!
            .scaleEffect(configuration.isPressed ? pushBackScale : 1.0)
    }
}
like image 122
Asperi Avatar answered Jan 05 '23 17:01

Asperi