UIButton action is not working in SwiftUI application.

Hello,

I'm trying to add floating UIButton on the top of UIHostingController view and found weird thing.

Action of the UIButton is not working if there is Button (from SwiftUI) underneath UIButton. Action is working if there is no Button underneath.

Why action of UIButton is not working?

Tested with iOS 15.4

Show your code, then we can suggest why it is not working.

Minimal reproducible example and some comments:

  1. Simple layout with single button. With console log on tap.
import SwiftUI

struct ContentView: View {
    var body: some View {
        VStack {
            Spacer()
            HStack {
                Spacer()
                Button {
                    print("bottom button tap")
                } label: {
                    Text("1234567890")
                }
            }
        }.padding()
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
  1. Inside of view "onAppear" I call "addButton" (UIButton)
import SwiftUI

@main
struct testApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView().onAppear {
                TestSDK.shared.addButton()
            }
        }
    }
}
  1. "addButton" is looking for view controller and view itself. Then adds UIButton inside view.
class TestSDK {
    private var button: UIButton?

    static let shared: TestSDK = {
        let instance = TestSDK()
        return instance
    }()

    func addButton() {
        if self.button != nil  {
            self.removeButton()
        }
        self.setupButton()
    }

    func removeButton() {
        if let button = self.button {
            button.removeFromSuperview()
            self.button = nil
        }
    }

    fileprivate func setupButton() {
        guard let root = self.keyWindowPresentedController else {
            return
        }

        guard let view = root.view else {
            return
        }

        self.button = UIButton(frame: .zero)

        guard let button = self.button else {
            return
        }

        button.addTarget(self, action: #selector(buttonAction), for: .touchUpInside)
        button.backgroundColor = .red

        view.addSubview(button)
        view.bringSubviewToFront(button)
        button.translatesAutoresizingMaskIntoConstraints = false

        let views = ["button" : button]
        let verticalButton = NSLayoutConstraint.constraints(withVisualFormat: "V:|-(>=0@299)-[button(64)]-40-|", options: NSLayoutConstraint.FormatOptions(), metrics: nil, views: views)
        let horizontalButton = NSLayoutConstraint.constraints(withVisualFormat: "H:|-(>=0@299)-[button(64)]-20-|", options: NSLayoutConstraint.FormatOptions(), metrics: nil, views: views)
        view.addConstraints(verticalButton + horizontalButton)
    }

    @objc func buttonAction() {
        print("top button tap")
    }
}

extension TestSDK {
    var keyWindow: UIWindow? {
        return UIApplication
            .shared
            .connectedScenes
            .flatMap { ($0 as? UIWindowScene)?.windows ?? [] }
            .first { $0.isKeyWindow }
    }

    var keyWindowPresentedController: UIViewController? {
        var viewController = self.keyWindow?.rootViewController

        if let presentedController = viewController as? UITabBarController {
            viewController = presentedController.selectedViewController
        }

        while let presentedController = viewController?.presentedViewController {
            if let presentedController = presentedController as? UITabBarController {
                viewController = presentedController.selectedViewController
            } else {
                viewController = presentedController
            }
        }
        return viewController
    }
}
  1. UIButton has action. But it is not working - once you will try tap UIButton you will see that action from bottom button is called.

Not clear what you are trying to achieve, but, you create button with zero frame:

        self.button = UIButton(frame: .zero)

Why ? May be you see the button below, as the new button is zero frame ?

Try by giving a non zero frame. Or set colour of SwiftUI button to blue, to be sure of what you tap on.

UIButton action is not working in SwiftUI application.
 
 
Q