How to disable with ButtonStyle in SwiftUI

Issue #853

With ButtonStyle, the disabled modifier does not seem to work, we need to use allowsHitTesting.

swift
import SwiftUI

struct ActionButtonStyle: ButtonStyle {
    func makeBody(configuration: Configuration) -> some View {
        HStack {
            Text("Button")
        }
        .padding()
        .disabled(true) // does not work
        .allowsHitTesting(false)
    }
}

We need to call disabled outside, after buttonStyle. In case we have onTapGesture on the entire view, touching on that disabled button will also trigger our whole view action, which is not what we want.

swift
VStack {
    Button(action: onSave) {
        Text("Save")
    }
    .buttonStyle(ActionButtonStyle())
    .disabled(true)
}
.onTapGesture {
    window.endEditing(true)
}

Another way is to overlay with a dummy view with a dummy tap gesture to obscure the action

swift
extension View {
    func disableInteraction(_ shouldDisable: Bool) -> some View {
        disabled(shouldDisable)
            .overlay(
                Group {
                    if shouldDisable {
                        DummyView()
                            .onTapGesture {}
                    }
                }
            )
    }
}

private struct DummyView: UIViewRepresentable {
    func makeUIView(context: Context) -> UIView {
        let view = UIView()
        return view
    }

    func updateUIView(_ uiView: UIView, context: Context) {}
}

So that we have

swift
Button(action: onSave) {
    Text("Save")
}
.buttonStyle(ActionButtonStyle())
.disableInteraction(true)
Written by

I’m open source contributor, writer, speaker and product maker.

Start the conversation