Caleb Rudnicki
Caleb Rudnicki

Reputation: 385

SwiftUI Button with UIView

I am making a SwiftUI Button from a custom UIButton class called UIPillButton. Here is the code for creating the SwiftUI button:

Button(action: {
    print("Button tapped")
}) {
    PillButton()
        .padding(.top)
}

Here is my class for creating a SwiftUI view called PillButton which converts my custom UIButton over:

struct PillButton: UIViewRepresentable {
    var ntPillButton = NTPillButton(type: .filled, title: "Start Test")
    
    func makeCoordinator() -> Coordinator { Coordinator(self) }
    
    class Coordinator: NSObject {
        var parent: PillButton
        
        init(_ pillButton: PillButton) {
            self.parent = pillButton
            super.init()
        }
    }

    func makeUIView(context: UIViewRepresentableContext<PillButton>) -> UIView {
        let view = UIView()
        view.addSubview(ntPillButton)
        
        NSLayoutConstraint.activate([
            ntPillButton.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            ntPillButton.trailingAnchor.constraint(equalTo: view.trailingAnchor)
        ])
        
        return view
    }

    func updateUIView(_ uiView: UIView, context: UIViewRepresentableContext<PillButton>) {}
}

The issue is that the Button is not running the action if I tap on the PillButton itself. It only works if I select the buffer (padding) space above the PillButton. How can I make it so I can use the custom PillButton class as a normal SwiftUI button?

screenshot

Upvotes: 6

Views: 6555

Answers (1)

Asperi
Asperi

Reputation: 257563

It is not clear what is NTPillButton, but if it is subclass of UIButton then the following demo of generic approach (using base UIButton) should clear and applicable.

Tested with Xcode 11.4 / iOS 13.4

The below gives this simple usage

    PillButton(title: "Start Test") {
        print("Button tapped")
    }
    .frame(maxWidth: .infinity)       // << screen-wide
    .padding(.top)

so now PillButton demo itself:

struct PillButton: UIViewRepresentable {
    let title: String
    let action: () -> ()

    var ntPillButton = UIButton()//NTPillButton(type: .filled, title: "Start Test")

    func makeCoordinator() -> Coordinator { Coordinator(self) }

    class Coordinator: NSObject {
        var parent: PillButton

        init(_ pillButton: PillButton) {
            self.parent = pillButton
            super.init()
        }

        @objc func doAction(_ sender: Any) {
            self.parent.action()
        }
    }

    func makeUIView(context: Context) -> UIButton {
        let button = UIButton(type: .system)
        button.setTitle(self.title, for: .normal)
        button.addTarget(context.coordinator, action: #selector(Coordinator.doAction(_ :)), for: .touchDown)
        return button
    }

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

Upvotes: 6

Related Questions