0

I followed this answer to create a button that is part of a second window that is on top of all other windows. It works fine with 1 button because it allows only that one button to get touch events, ignores everything else inside the second window, but the main window underneath of it still receives all of it touch events.

// This comment is from @robmayoff's answer
// As I mentioned, I need to override pointInside(_:withEvent:) so that the window ignores touches outside the button:

var button: UIButton?

private override func pointInside(point: CGPoint, withEvent event: UIEvent?) -> Bool {
    guard let button = button else { return false }
    let buttonPoint = convertPoint(point, toView: button)
    return button.pointInside(buttonPoint, withEvent: event)
}

The way I have it now inside the SecondWindow, I can receive touch events for the cancelButton but the other buttons get ignored along with everything else. The question is how do I receive touch events for the other buttons inside the second window but still ignore everything else?

The Second UIWindow. This is what I tried but it didn't work:

class SecondWindow: UIWindow {

    var cancelButton: UIButton?
    var postButton: UIButton? // I need this to also receive touch events
    var reloadButton: UIButton? // I need this to also receive touch events

    init() {
        super.init(frame: UIScreen.main.bounds)
        backgroundColor = nil
    }

    override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {

        if let cancelButton = cancelButton {
            let cancelButtonPoint = convert(point, to: cancelButton)
            return cancelButton.point(inside: cancelButtonPoint, with: event)
        }

        if let postButton = postButton {
            let postButtonPoint = convert(point, to: postButton)
            return postButton.point(inside: postButtonPoint, with: event)
        }

        if let reloadButton = reloadButton {
            let reloadButtonPoint = convert(point, to: reloadButton)
            return reloadButton.point(inside: reloadButtonPoint, with: event)
        }

        return false
    }

    override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
        let hitView = super.hitTest(point, with: event)
        guard let safeHitView = hitView else { return nil }
        if safeHitView.isKind(of: SecondController.self) { return nil }
        return safeHitView
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

The vc with the buttons:

class SecondController: UIViewController {

    lazy var cancelButton: UIButton = { ... }()

    lazy var postButton: UIButton = { ... }()

    lazy var reloadButton: UIButton = { ... }()

    let window = SecondWindow()

    init() {
        super.init(nibName: nil, bundle: nil)

        window.frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)

        window.cancelButton = cancelButton
        window.postButton = postButton
        window.reloadButton = reloadButton

        window.isHidden = false
        window.backgroundColor = .clear
        window.rootViewController = self
        window.windowLevel = UIWindow.Level.normal
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .clear

        // Anchors for buttons
    }
}
Lance Samaria
  • 17,576
  • 18
  • 108
  • 256

1 Answers1

0

I check to see if the point touched is inside the receiver (whichever button is touched). If it is it returns true then the touch is acknowledged and the button responds, if it's not it does nothing and skips to the next button, checks there and repeats the process until the last button and the same process is repeated.

override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {

    guard let cancelButton = cancelButton, let postButton = postButton, let reloadButton = reloadButton else {
        return false
    }

    let cancelButtonPoint = convert(point, to: cancelButton)
    let cancelBool = cameraButton.point(inside: cameraButtonPoint, with: event)
    if cancelBool {
        return cancelButton.point(inside: cancelButtonPoint, with: event)
    }

    let postButtonPoint = convert(point, to: postButton)
    let postBool = postButton.point(inside: postButtonPoint, with: event)
    if postBool {
        return postButton.point(inside: postButtonPoint, with: event)
    }

    let reloadButtonPoint = convert(point, to: reloadButton)
    return reloadButton.point(inside: reloadsButtonPoint, with: event)
}
Lance Samaria
  • 17,576
  • 18
  • 108
  • 256