Как использовать UIBlurEffect с модальными контроллерами View?
У меня есть UIViewController
, который представляет другой UIViewController
по модулю. Я хочу, чтобы контроллер модального представления имел размытие/прозрачность, введенное iOS 7. Я попытался использовать новый UIVisualEffect
, но похоже, что работает только с UIViews
, а не UIViewControllers
?
Вот код, который я написал, все представления, которые я добавил в качестве подзонов, - это то, что я хочу быть в пользовательском интерфейсе над размытым видом под ним.
В представлении контроллера представления, я делаю скриншот экрана, который я передаю в контроллер модального представления, прежде чем применять размытие.
В представлении контроллера представления:
- (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:
- (void)viewDidLoad {
[super viewDidLoad];
[self.view addSubview:[[UIImageView alloc] initWithImage:self.backgroundImage]];
//self.backgroundImage is the image that the method above returns, it 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];
}
Ответы
Ответ 1
При использовании 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)
}
}
Ответ 2
В Swift 3
Я обнаружил, что если вы берете, то делает модальный переход к новому UIViewController и имеет его в контексте с четким фоном, чтобы вы могли видеть последний VC. Использование представления UIVisualEffect, установленного в IB, работает неправильно. То, что вы получите, - это размытие, которое отображается в конце презентации нового представления.
В конструкторе интерфейса:
Постройте модальный переход к другому виду, сделайте Вид: Присутствует Модиально, Переход: Крест Fade. Затем дайте ему идентификатор типа "showMainMenu".
В целевом VC установите его так, чтобы первое представление представляло собой UIImageView с параметром AspectToFit, причем сторона была установлена в 0-0-0-0 с каждой стороны для ограничений. Второй SubView - это UIBlurView, установленный в 0-0-0-0 по бокам VC.
Затем поместите свои элементы поверх UIBlurView, как приятный контрастный текст.
Создайте var для фона, чтобы установить 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 ниже вашего текущего, вы можете увидеть его под размытием.
Надеюсь, это поможет!
Не забудьте проверить демонстрационный проект в моем git!
https://github.com/yungdai/Smooth-blur-transition-using-storyboard
Ответ 3
Благодаря @YarGnawh. Это протестировано на iOS 8
UIBlurEffect *blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight];
UIVisualEffectView *blurEffectView = [[UIVisualEffectView alloc] initWithEffect:blurEffect];
[blurEffectView setFrame:self.view.bounds];
self.tableView.backgroundView = blurEffectView;
Ответ 4
Это сочетание вышеупомянутых ответов.
Это работает для конструктора интерфейса в Xcode 7.2.1 (Swift 2.1.) для iOS 9.2.1.
Код был протестирован на симуляторе и устройстве.
В интерфейсе Builder:
- Нажмите кнопку раскадровки.
- Как "Добрый" набор "Настоящий Модиально"
- Как "Презентация", установите "Over Current Context"
ПРИМЕЧАНИЕ. Установка третьего шага в
viewDidLoad
презентации UIViewController
не будет работать.
- Не забудьте нажать
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)
}
}
Ответ 5
Посмотрите на мой примерный проект, где я демонстрирую эффект размытия, используя только раскадров и ограничения.
Демо-версия GitHub: ссылка
Ответ 6
Самый простой способ - просто скопировать и вставить этот код в viewDidLoad:)
UIVisualEffect *blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight];
UIVisualEffectView *visualEffectView = [[UIVisualEffectView alloc] initWithEffect:blurEffect];
visualEffectView.frame = self.view.bounds;
self.view insertSubview:visualEffectView atIndex:0];