【问题标题】:How to use UIBlurEffect with modal View Controllers?如何将 UIBlurEffect 与模态视图控制器一起使用?
【发布时间】:2014-08-15 12:44:27
【问题描述】:

我有一个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;
}

在模态视图控制器中:

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

【问题讨论】:

标签: ios iphone objective-c user-interface


【解决方案1】:

使用 UIVisualEffectView 时,不需要生成快照。尝试删除“- (UIImage *)viewImage”并在模型视图控制器中添加一个尺寸与视图控制器视图匹配的 UIVisualEffectView,并将所有“控制”视图添加到 UIVisualEffectView 的 contentView 中。

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

我还没有在故事板中尝试过,但这里有一个经过测试的工作 sn-p。可能是一个很好的起点。翻译成 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)
}
}

【讨论】:

  • 这给了我一个空白的背景,下面没有任何模糊的东西。我希望呈现它的视图控制器在下面可见但模糊。
  • 你是如何展示模态的?
  • @ProgramGuy 检查上面的更新代码。记笔记! modal.modalPresentationStyle = UIModalPresentationStyle.OverCurrentContext
  • OverCurrentContext 的好电话,甚至在故事板中都没有看到该选项!
  • Interface Builder方式:在IB中,选择segue,在属性检查器中,有一个选项叫Presentation,你可以在那里选择Over Current Context。跨度>
【解决方案2】:

看看我的示例项目,我只使用 storyboardconstraints 来演示模糊效果。

GitHub 演示:link

【讨论】:

    【解决方案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】:

      这是上述答案的组合。

      这适用于 iOS 9.2.1 的 Xcode 7.2.1 (Swift 2.1.) 中的 Interface builder。

      代码已经在模拟器和设备上测试过了。

      在界面生成器中:

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

      【讨论】:

        【解决方案5】:

        在 Swift 3 中

        我发现如果你正在做一个模态转换到一个新的 UIViewController 并让它在上下文中具有清晰的背景,这样你就可以看到最后一个 VC。使用 IB 中设置的 UIVisualEffect 视图无法正常工作。您将得到它是在新视图演示结束时呈现的模糊。

        在界面生成器中:

        为另一个视图构建模态转场,使 Kind: Present Modally,Transition: Cross Fade。然后给它一个标识符,如“showMainMenu”。

        在目标 VC 中,将其设置为第一个视图是设置了 AspectToFit 的 UIImageView,边设置为 0-0-0-0 到约束的每一边。第二个 SubView 是一个 UIBlurView 设置为 0-0-0-0 到 VC 的两侧。 然后将您的元素放在 UIBlurView 的顶部,就像漂亮的对比文本一样。

        为背景创建一个 var 以设置为您将继续使用的 VC 的 UIImageView。

        var 背景: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
                }
        
        }
        

        然后在我的 segue 中,我执行以下操作:

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

        一旦 segued,确保在新的视图控制器中运行它。

        // 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 in!另外,如果您在当前 VC 下方的最后一个 VC 上有移动元素,您可以在模糊下看到它。

        希望这会有所帮助!

        随意在我的 git 中签出一个演示项目!

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

        【讨论】:

          【解决方案6】:

          最简单的方法就是复制这段代码并将其粘贴到 viewDidLoad :)

          UIVisualEffect *blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight];
          UIVisualEffectView *visualEffectView = [[UIVisualEffectView alloc] initWithEffect:blurEffect];
          
          visualEffectView.frame = self.view.bounds;
          self.view insertSubview:visualEffectView atIndex:0];
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2013-10-24
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多