I have a UIViewController
that presents another UIViewController
modally. I want the modal view controller to have the blur/transparency that iOS 7 int
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