7

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

1 Answer 1

6

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) {}
}
Sign up to request clarification or add additional context in comments.

3 Comments

Yes that works. However, my custom UIButton (NTPillButton) is made to only fit the size of the text so the button does not span the width of the screen like I aim for it to. Is there a way to pin the PillButton to the edges of the screen? Maybe with an HStack?
@CalebRudnicki, just use .frame modifier. See updated.
That's not quite it. The UIButton that the PillButton is inheriting from is only filling the amount of space it needs to fit the button text. Can i make the button span the whole width in swiftui code or will that have to be done in my UIButton's class?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.