How to use UIBlurEffect with modal View Controllers?

后端 未结 6 2306
夕颜
夕颜 2021-02-13 14:17

I have a UIViewController that presents another UIViewController modally. I want the modal view controller to have the blur/transparency that iOS 7 int

相关标签:
6条回答
  • 2021-02-13 14:56

    In Swift 3

    I found that if you take are doing a modal transition to a new UIViewController and have it over the context with a clear background so you can see the last VC. Using a UIVisualEffect view set in IB doesn't work properly. What you will get it is the blur being rendered at the end of your presentation of the new view.

    In interface builder:

    Build a modal segue to another view, make the Kind: Present Modally, Transition: Cross Fade. Then give it an identifier like "showMainMenu".

    In the destination VC, set it so the first view is a UIImageView with AspectToFit set, with the side set to 0-0-0-0 to each side for the constraints. Second SubView is a UIBlurView set to 0-0-0-0 to the sides of the VC. Then put your elements on top of the UIBlurView like nice contrasty text.

    Create a var for the background to set to the UIImageView of the VC you will be segueing to.

    var background: UIImage! = UIImage()

    Run the segue now and you'll notice the blur pops in and looks terrible.

    To solved this issue, write some code to take a snapshot with this extension code for UIImage

        extension UIImage {
    
            class func takeScreenshot(view: UIView) -> UIImage? {
    
                // Create screenshot
                UIGraphicsBeginImageContext(view.bounds.size)
    
                view.layer.render(in: UIGraphicsGetCurrentContext()!)
                let screenshot:UIImage = UIGraphicsGetImageFromCurrentImageContext()!
                UIGraphicsEndImageContext()
                print("Taking Screenshot")
    
                UIGraphicsEndImageContext()
                return screenshot
            }
    
    }
    

    Then in my segue I do the following:

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    
        if segue.identifier == "showMainMenu" {
    
            let vc = segue.destination as! MainViewController
    
            // I am using a VERY long scroll view so self.view.window! ensures that you only take a picture of your actual view instead of a view that is longer than your screen size.
            let screenshot: UIImage = UIImage.takeScreenshot(view: self.view.window!)!
    
            vc.background = screenshot
    
        }
    }
    

    once segued, in the new view controller make sure you run this.

    // set the image over to the background image. 
    
    
        override func viewWillAppear(_ animated: Bool) {
            super.viewWillAppear(animated)
            self.backgroundImage.image = background
    
        }
    
        override func viewDidAppear(_ animated: Bool) {
            super.viewDidAppear(animated)
    
    
            // prevent the blurView for just popping in due to the segue
            UIView.animate(withDuration: 0.3, delay: 0.0, options: .curveEaseInOut, animations: {
    
                // make the background transparent so you can now see what is beneath that layer.
                self.backgroundImage.alpha = 0
            })
        }
    

    This way you can get the sweet modal IB Fade in without too much code! Plus when if you have moving elements on the last VC beneath your current one, you can see it under the blur.

    Hope this helps!

    Feel free to checkout a demonstration project in my git!

    https://github.com/yungdai/Smooth-blur-transition-using-storyboard

    0 讨论(0)
  • 2021-02-13 14:57

    This is a combination of the above answers.

    This works for Interface builder in Xcode 7.2.1 (Swift 2.1.) for iOS 9.2.1.

    The code has been tested on the simulator and device.

    In Interface Builder:

    1. Click the storyboard seque
    2. As "Kind" set "Present Modally"
    3. As "Presentation" set "Over Current Context" NOTE: Setting the 3.rd step in you viewDidLoadof the presenting UIViewController will not work
    4. Dont forget to click your UIViewController and under Custom Class"- Class name it YOUTransparentModalVC (or whatever you want).

    In code:

    import UIKit
    
    let IMAGE_OVERLAY_NAME = "backgroundColorExample"
    
    class YOUTransparentModalVC: UIViewController
    {
        private var backgroundImageOverlayIV:UIImageView!
    
        override func viewDidLoad()
        {
            super.viewDidLoad()
            self.setupTransparentView()
            self.setupDissmissingVCOnTap()
            self.setupBackgroudImage()
        }
    
        private func setupTransparentView()
        {
            self.view.backgroundColor       = UIColor.clearColor()
            let effect                      = UIBlurEffect(style: UIBlurEffectStyle.Light)
            let blurView                    = UIVisualEffectView(effect: effect)
            blurView.frame                  = self.view.bounds
            self.view.addSubview(blurView)
        }
    
        private func setupBackgroudImage()
        {
            self.backgroundImageOverlayIV            = UIImageView(frame: self.view.frame)
            self.backgroundImageOverlayIV.image      = UIImage(named: IMAGE_OVERLAY_NAME)
            self.view.addSubview(self.backgroundImageOverlayIV)
        }
    
        private func setupDissmissingVCOnTap()
        {
            let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: "dismissVC")
            view.addGestureRecognizer(tap)
        }
    
        func dismissVC()
        {
            self.dismissViewControllerAnimated(true, completion: nil)
        }
    
    
    }
    
    0 讨论(0)
  • 2021-02-13 14:59

    Thanks to @YarGnawh. This tested on iOS 8

    UIBlurEffect *blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight];
    UIVisualEffectView *blurEffectView = [[UIVisualEffectView alloc] initWithEffect:blurEffect];
    [blurEffectView setFrame:self.view.bounds];
    self.tableView.backgroundView = blurEffectView;
    
    0 讨论(0)
  • 2021-02-13 15:00

    When using UIVisualEffectView, you don't need to generate a snapshot. Try removing "- (UIImage *)viewImage" and in the model view controller add a UIVisualEffectView with size matching the view controller view, and add all "control" views into the UIVisualEffectView's contentView.

    - (void)viewDidLoad {
        [super viewDidLoad];
    
        UIBlurEffect *blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight];
        UIVisualEffectView *blurEffectView = [[UIVisualEffectView alloc] initWithEffect:blurEffect];
        [blurEffectView setFrame:self.view.bounds];
        [self.view addSubview:blurEffectView];
    
        [blurEffectView.contentView addSubview:self.cancelButton];
        [blurEffectView.contentView addSubview:self.titleLabel];
        [blurEffectView.contentView addSubview:self.tableView];
    }
    

    https://developer.apple.com/library/prerelease/ios/documentation/UIKit/Reference/UIVisualEffectView/index.html

    I haven't tried it with storyboards, but here's a tested working snippet. Might be a good place to start. Translating to objc should be pretty straightfoward

    Here's the presenting view controller

    import UIKit
    
    class BaseViewController: UIViewController {
    
    init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
        super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
    
        var backgroundImage = UIImageView(image: UIImage(named: "image"))
        self.view.addSubview(backgroundImage)
    
        var button = UIButton(frame: CGRectMake(0, 100, 320, 50))
        button.setTitle("Lorem Ipsum", forState: UIControlState.Normal)
        button.backgroundColor = UIColor.redColor()
        button.addTarget(self, action: "onButtonTapped:", forControlEvents: UIControlEvents.TouchUpInside)
    
        self.view.addSubview(button)
    }
    
    func onButtonTapped(sender: UIButton?) {
        var modal = ModalViewController(nibName: nil, bundle: nil)
        modal.modalPresentationStyle = UIModalPresentationStyle.OverCurrentContext
        self.presentViewController(modal, animated: true, completion: {})
    }
    }
    

    Here's the modal

    import UIKit
    
    class ModalViewController: UIViewController {
    
    init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
        super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
    
        self.view.backgroundColor = UIColor.clearColor()
    
        let effect = UIBlurEffect(style: UIBlurEffectStyle.Light)
        let blurView = UIVisualEffectView(effect: effect)
    
        blurView.frame = self.view.bounds
    
        self.view.addSubview(blurView)
    }
    }
    
    0 讨论(0)
  • 2021-02-13 15:07

    the easiest way is just copy and paste this code in viewDidLoad :)

    UIVisualEffect *blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight];
    UIVisualEffectView *visualEffectView = [[UIVisualEffectView alloc] initWithEffect:blurEffect];
    
    visualEffectView.frame = self.view.bounds;
    self.view insertSubview:visualEffectView atIndex:0];
    
    0 讨论(0)
  • 2021-02-13 15:09

    Look at my sample project where I demonstrate blur effect by using only storyboard and constraints.

    GitHub demo: link

    0 讨论(0)
提交回复
热议问题