iosswiftfrontenduivisualeffectviewuiblureffect

Blurred overlay does not cover entire screen


I'm trying to display a blurred background over a ViewController that contains a UITableView and is displayed modally. But I can't seem to get the blur effect to cover the entire screen, specifically the Navigation and Status Bars. Below is a screenshot of the blur effect covering the area below the Navigation Bar but not above it -- this happens when I set the frame of the UIVisualEffectView to view.bounds. (Note: The blur effect is designed to be displayed at the same time as the title screen w/ keyboard, and the title screen has a clear + non-opaque background to accommodate this blur effect.)

enter image description here

Interestingly, when I set the frame of the UIVisualEffectView to view.frame (rather than view.bounds), the blur effect only covers about 2/3rds of the area that view.bound covers. Not sure why it's doing this.

Below is what I have in my code. As you can see, when the 'Done' button is pressed, the app generates the ActionViewController (the title screen) along with the blurred background which is called through a delegate method.

@IBAction func donePressed(_ sender: UIButton) {
    let vc = ActionViewController()
    self.definesPresentationContext = true
    self.providesPresentationContextTransitionStyle = true
    vc.modalPresentationStyle = .overFullScreen
    vc.modalTransitionStyle = .coverVertical
    
    self.present(vc, animated: true, completion: nil)
    self.overlayBlurredBackgroundView()
    vc.delegate = self
}

extension PreviewViewController: ActionViewControllerDelegate {
    func overlayBlurredBackgroundView() {
        let blurredBackgroundView = UIVisualEffectView()
        blurredBackgroundView.frame = view.bounds
        blurredBackgroundView.effect = UIBlurEffect(style: .systemThinMaterialDark)
        view.addSubview(blurredBackgroundView)
}

Solution

  • First off, what Muhammad suggested should work. The reason your code crashes could be you are attempting to add the constraints first before adding the blurView to your view as a subview. The key phrase is:

    they have no common ancestor.

    Don't do that. Always add your subview before constraining it.


    Lastly, one easy way to achieve what you want to achieve is to just toggle your navigationBar's visibility whenever you present your transparent screen (the one with the keyboard) and then put the navigationBar back to visible when you're done. Like so:

    func overlayBlurredBackgroundView() {
      self.navigationController?.navigationBar.isHidden = true
      
        let blurredBackgroundView = UIVisualEffectView()
        //blurredBackgroundView.frame = view.bounds
        blurredBackgroundView.effect = UIBlurEffect(style: .systemThinMaterialDark)
        view.addSubview(blurredBackgroundView)
      
        blurredBackgroundView.translatesAutoresizingMaskIntoConstraints = false
        blurredBackgroundView.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 0.0).isActive = true
        blurredBackgroundView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor, constant: 0.0).isActive = true
        blurredBackgroundView.leftAnchor.constraint(equalTo: self.view.leftAnchor, constant: 0.0).isActive = true
        blurredBackgroundView.rightAnchor.constraint(equalTo: self.view.rightAnchor, constant: 0.0).isActive = true
    
    }
    

    and then putting it back when you're removing it:

    func removeBlurredBackgroundView() {
      self.navigationController?.navigationBar.isHidden = false
        for subview in view.subviews {
            if subview.isKind(of: UIVisualEffectView.self) {
                subview.removeFromSuperview()
            }
        }
    }