Как использовать UIBlurEffect с модальными контроллерами вида?

У меня есть UIViewController это представляет другой UIViewController модально. Я хочу, чтобы модальный контроллер вида имел размытие / прозрачность, которую представил iOS 7. Я пытался использовать новый UIVisualEffect но похоже, что это работает только с UIViews, и не UIViewControllers?

Вот код, который я написал, все представления, которые я добавил как подпредставления, - это то, что я хочу видеть в пользовательском интерфейсе над размытым представлением под ним.

В представляемом контроллере представления я делаю снимок экрана, который я передаю модальному контроллеру представления перед применением размытия.

В представлении View Controller:

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

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

6 ответов

В Свифт 3

Я обнаружил, что если вы беретесь за модальный переход к новому UIViewController и имеете его в контексте с четким фоном, чтобы вы могли видеть последний VC. Использование вида представления UIVisualEffect в IB не работает должным образом. То, что вы получите, это размытие, отображаемое в конце представления нового представления.

В конструкторе интерфейса:

Создайте модальный переход к другому представлению, сделайте Вид: Представить модально, Переход: Перекрестное затухание. Затем присвойте ему идентификатор типа "showMainMenu".

В целевом виртуальном канале установите его так, чтобы первым представлением был UIImageView с установленным AspectToFit, с стороной, установленной на 0-0-0-0 с каждой стороны для ограничений. Второй SubView - это UIBlurView, установленный в 0-0-0-0 по сторонам VC. Затем поместите ваши элементы поверх UIBlurView, как красивый контрастный текст.

Создайте переменную для фона, чтобы установить UIImageView VC, к которому вы будете обращаться.

var background: UIImage! = UIImage ()

Запустите Segue сейчас, и вы заметите, что размытие появляется и выглядит ужасно.

Чтобы решить эту проблему, напишите некоторый код, чтобы сделать снимок с этим кодом расширения для 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
        }

}

Затем в моем случае я делаю следующее:

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

    }
}

после того, как будет запущен, в новом контроллере вида убедитесь, что вы запустите это

// 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
        })
    }

Таким образом, вы можете получить симпатичный модальный IB Fade без лишнего кода! Плюс, если у вас есть движущиеся элементы на последнем VC под вашим текущим, вы можете увидеть его под размытием.

Надеюсь это поможет!

Не стесняйтесь проверить демонстрационный проект в моем мерзавце!

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

При использовании UIVisualEffectView вам не нужно создавать снимок. Попробуйте удалить "- (UIImage *)viewImage" и в контроллере представления модели добавьте UIVisualEffectView с размером, совпадающим с представлением контроллера представления, и добавьте все "управляющие" представления в представление содержимого 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

Я не пробовал это с раскадровками, но вот проверенный рабочий фрагмент. Может быть, это хорошее место для начала. Перевод на objc должен быть довольно простым

Вот представление контроллера представления

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: {})
}
}

Вот модал

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

Самый простой способ - просто скопировать и вставить этот код в viewDidLoad:)

UIVisualEffect *blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight];
UIVisualEffectView *visualEffectView = [[UIVisualEffectView alloc] initWithEffect:blurEffect];

visualEffectView.frame = self.view.bounds;
self.view insertSubview:visualEffectView atIndex:0];

Спасибо @YarGnawh. Это проверено на iOS 8

UIBlurEffect *blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight];
UIVisualEffectView *blurEffectView = [[UIVisualEffectView alloc] initWithEffect:blurEffect];
[blurEffectView setFrame:self.view.bounds];
self.tableView.backgroundView = blurEffectView;

Это комбинация приведенных выше ответов.

Это работает для Интерфейсного разработчика в Xcode 7.2.1 (Swift 2.1.) Для iOS 9.2.1.

Код был протестирован на симуляторе и устройстве.

В Интерфейсном Разработчике:

  1. Нажмите на раскадровку
  2. Как "Добрый" набор "Подари модально"
  3. В качестве "Презентации" установите "Над текущим контекстом". ПРИМЕЧАНИЕ. viewDidLoadпредставления UIViewController не будет работать
  4. Не забудьте нажать на ваш UIViewController и под Custom Class"- Class назови это YOUTransparentModalVC (или что хочешь).

В коде:

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


}

Посмотрите на мой пример проекта, где я демонстрирую эффект размытия, используя только раскадровку и ограничения.

GitHub demo: ссылка

Другие вопросы по тегам