J'ai une UIViewController
qui présente une autre UIViewController
modale. Je souhaite que le contrôleur de vue modale ait le flou/transparence introduit par iOS 7. J'ai essayé d'utiliser la nouvelle variable UIVisualEffect
, mais il semble que cela ne fonctionne qu'avec UIViews
et pas UIViewControllers
?
Voici le code que j'ai écrit. Toutes les vues que j'ai ajoutées en tant que sous-vues correspondent à ce que je veux être dans l'interface utilisateur, au-dessus de la vue floue en dessous.
Dans le contrôleur de vue de présentation, je prends une capture d'écran de l'écran que je passe au contrôleur de vue modale avant d'appliquer le flou.
Dans le contrôleur de vue de présentation:
- (UIImage *)viewImage {
CGSize size = CGSizeMake(self.view.frame.size.width,self.view.frame.size.height);
UIGraphicsBeginImageContext(size);
[self.view drawViewHierarchyInRect:(CGRect){CGPointZero, self.view.frame.size.width, self.view.frame.size.height} afterScreenUpdates:YES];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
Dans Modal View Controller:
- (void)viewDidLoad {
[super viewDidLoad];
[self.view addSubview:[[UIImageView alloc] initWithImage:self.backgroundImage]];
//self.backgroundImage is the image that the method above returns, it's a screenshot of the presenting view controller.
UIBlurEffect *blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight];
UIVisualEffectView *blurEffectView = [[UIVisualEffectView alloc] initWithEffect:blurEffect];
[blurEffectView setFrame:self.view.bounds];
[self.view addSubview:blurEffectView];
[self.view bringSubviewToFront:self.cancelButton];
[self.view bringSubviewToFront:self.titleLabel];
[self.view bringSubviewToFront:self.tableView];
}
Lorsque vous utilisez UIVisualEffectView, vous n'avez pas besoin de générer un instantané. Essayez de supprimer "- (UIImage *) viewImage" et, dans le contrôleur de vue modèle, ajoutez un UIVisualEffectView de taille correspondant à la vue du contrôleur de vue, puis ajoutez toutes les vues "contrôle" dans le contentView de UIVisualEffectView.
- (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];
}
Je n'ai pas essayé avec les scénarimages, mais voici un extrait de travail testé. Peut-être un bon endroit pour commencer. Traduire en objc devrait être assez simple
Voici le contrôleur de vue de présentation
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: {})
}
}
Voici le 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)
}
}
Dans Swift 3
J'ai constaté que si vous prenez effectuez une transition modale vers un nouveau UIViewController et que vous l'avez sur le contexte avec un arrière-plan clair afin que vous puissiez voir le dernier VC. L'utilisation d'une vue UIVisualEffect définie dans IB ne fonctionne pas correctement. Ce que vous obtiendrez, c'est le flou rendu à la fin de votre présentation de la nouvelle vue.
Dans le constructeur d'interface:
Construisez une transition modale vers une autre vue, faites ce qui suit: Transition: Transition en fondu. Puis donnez-lui un identifiant du type "showMainMenu".
Dans le VC de destination, définissez-le de sorte que la première vue soit une UIImageView avec AspectToFit définie, avec le côté défini sur 0-0-0-0 de chaque côté pour les contraintes. Second SubView est un UIBlurView défini sur 0-0-0-0 sur les côtés du VC. Ensuite, placez vos éléments au-dessus de UIBlurView comme un joli texte contrasté.
Créez une variable pour l'arrière-plan à définir sur UIImageView du VC que vous allez suivre.
var background: UIImage! = UIImage ()
Lancez la transition maintenant et vous remarquerez que le flou apparaît et est affreux.
Pour résoudre ce problème, écrivez du code afin de prendre un instantané avec ce code d'extension pour 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
}
}
Puis dans ma suite je fais ce qui suit:
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
}
}
une fois séparé, dans le nouveau contrôleur de vue, assurez-vous de l'exécuter.
// 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
})
}
De cette façon, vous pouvez obtenir le doux modal IB Fade in sans trop de code! De plus, si vous avez des éléments en mouvement sur le dernier VC situé sous votre élément actuel, vous pouvez le voir sous le flou.
J'espère que cela t'aides!
N'hésitez pas à commander un projet de démonstration dans mon git!
https://github.com/yungdai/Smooth-blur-transition-using-storyboard
le plus simple est de copier et coller ce code dans viewDidLoad :)
UIVisualEffect *blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight];
UIVisualEffectView *visualEffectView = [[UIVisualEffectView alloc] initWithEffect:blurEffect];
visualEffectView.frame = self.view.bounds;
self.view insertSubview:visualEffectView atIndex:0];
Merci à @YarGnawh. Cette testé sur iOS 8
UIBlurEffect *blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight];
UIVisualEffectView *blurEffectView = [[UIVisualEffectView alloc] initWithEffect:blurEffect];
[blurEffectView setFrame:self.view.bounds];
self.tableView.backgroundView = blurEffectView;
Ceci est une combinaison des réponses ci-dessus.
Cela fonctionne pour le constructeur d'interface dans Xcode 7.2.1 (Swift 2.1.) Pour iOS 9.2.1.
Le code a été testé sur le simulateur et le périphérique.
Dans Interface Builder:
viewDidLoad
de la présentation UIViewController
ne fonctionnera pasUIViewController
et sous Custom Class
"- Class
nommez-le YOUTransparentModalVC
(ou ce que vous voulez).Dans du 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)
}
}
Regardez mon exemple de projet où je démontre l’effet de flou en utilisant seulement storyboard et contraintes .
Démo GitHub: link