web-dev-qa-db-fra.com

Comment utiliser UIBlurEffect avec les contrôleurs de vue modaux?

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];
}
13
user594161

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];
}

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

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)
}
}
11
YarGnawh

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

9
Yung Dai

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];
1
Pedro Romão

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;
1
Mazen Kasser

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:

  1. Cliquez sur le seque du storyboard
  2. Comme "genre" set "Présent Modally"
  3. En tant que "Présentation", définissez "Sur le contexte actuel" REMARQUE: Le réglage de la 3.ème étape en vous viewDidLoadde la présentation UIViewController ne fonctionnera pas
  4. N'oubliez pas de cliquer sur votre UIViewController 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)
    }


}
1
MB_iOSDeveloper

Regardez mon exemple de projet où je démontre l’effet de flou en utilisant seulement storyboard et contraintes .

Démo GitHub: link

0
vaberer