0
votes

I'm trying to add a (background) mask view to the front most window in my iOS app. On that mask view I want to add a UITapGestureRecognizer that will dismiss the mask view. Ultimately, I want to display a popup in the middle (i.e. my mask view is a faded background for the popup), but for now I'm just having trouble getting my background to dismiss as expected.

The code looks like this: I get the front most window. I create the background view and add alpha. Then I add my gesture recognizer, add it to the window and add constraints.

However my tap gesture target didTapOnMaskView() never gets triggered.

private func createMaskView() {

    let applicationKeyWindow = UIApplication.shared.windows.last
    backgroundView = UIView()
    backgroundView.translatesAutoresizingMaskIntoConstraints = false
    backgroundView.backgroundColor = UIColor(white: 0, alpha: 0.2)

    backgroundDismissGesture = UITapGestureRecognizer(target: self, action: #selector(didTapOnMaskView))
    backgroundDismissGesture.numberOfTapsRequired = 1
    backgroundDismissGesture.cancelsTouchesInView = false;
    backgroundView.addGestureRecognizer(backgroundDismissGesture)
    backgroundView.isUserInteractionEnabled = true

    backgroundView.alpha = 0.0

    UIView.animate(withDuration: 0.4) { 
        self.backgroundView.alpha = 1.0
    }

    applicationKeyWindow.addSubview(backgroundView)

    let views: [String: UIView] = [ "backgroundView": backgroundView]

    var allConstraints = [NSLayoutConstraint]()

    let verticalConstraint = NSLayoutConstraint.constraints(withVisualFormat: "V:|-0-[backgroundView]-0-|", options: [], metrics: nil, views: views)
    allConstraints += verticalConstraint

    let horizontalConstraint = NSLayoutConstraint.constraints(withVisualFormat: "H:|-0-[backgroundView]-0-|", options: [], metrics: nil, views: views)
    allConstraints += horizontalConstraint

    NSLayoutConstraint.activate(allConstraints)

    // This is super odd, but the gesture gets triggered until the following code block executes
    DispatchQueue.main.asyncAfter(deadline: .now() + 3.1) {
        applicationKeyWindow.bringSubview(toFront: self.backgroundView)
    }
}


func didTapOnMaskView() {
    hide()
}

func show(){
    createMaskView()
}

** EDIT ** After running some more diagnostics, I've noticed that if I add a three-second-delayed block of code to the end of my createMaskView() that brings the maskView to the front, the gesture works for the first 3.1 seconds until that block of code is executed. Note that if that code block is not there, the gesture recognizer doesn't work at all (not even 3.1 seconds).

2

2 Answers

0
votes

Since you intend your background view to have the same size as its superview you could try setting the frame size instead of using constraints.

let backgroundView = UIView(frame: applicationKeyWindow.frame)

which has worked for me in the past in a similar situation.

I hope this helps! Have a nice day!

0
votes

As it turns out, not maintaining a reference to the View that contains my maskView was the issue. In the ViewController that creates this View I changed my showPopUp() function as follows:

// Stored property on my View Controller class
var myPopupView: UIView?

private func showLMBFormSubmittedPopup(){
    let popupView = MyPopupView()
    popupView.show()

    // Once I added this line, it started working
    myPopupView = popupView
}

Perhaps someone could shed some light on why this is occurring. I suspect that ARC is freeing up the memory that my UITapGestureRecognizer is occupying because my code no longer references it.