【问题标题】:UIVisualEffectView in iOS 10iOS 10 中的 UIVisualEffectView
【发布时间】:2017-02-01 22:36:29
【问题描述】:

我正在展示一个包含 UIVisualEffectView 的 UIViewController,如下所示:

-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
    [self performSegueWithIdentifier:@"segueBlur" sender:nil];
}

-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    if([segue.identifier isEqualToString:@"segueBlur"]) {
        ((UIViewController *)segue.destinationViewController).providesPresentationContextTransitionStyle = YES;
        ((UIViewController *)segue.destinationViewController).definesPresentationContext = YES;
        ((UIViewController *)segue.destinationViewController).modalPresentationStyle = UIModalPresentationOverFullScreen;
    }
}

如您所见,我正在使用 UIModalPresentationStyleOverFullScreen 以便当出现模糊的视图控制器时,模糊将“应用”到呈现它的视图控制器的内容; segue 有一个 Cross Dissolve 过渡风格。

效果符合预期。但是,在 iOS 9 中,呈现比在 iOS 10 中更流畅。在 iOS 10 中,当视图控制器出现时,它看起来像是一个 2 步动画,而在 iOS 9 中,模糊是立即应用的。

一张图片值一千字,所以我上传了一段视频来展示这种奇怪的行为:

UIVisualEffectView iOS 9 vs iOS 10

我的问题是:如何在 iOS 10 中像在 iOS 9 中一样呈现视图控制器?

【问题讨论】:

    标签: ios objective-c ios10 xcode8 uivisualeffectview


    【解决方案1】:

    iOS 10 改变了 UIVisualEffectView 的工作方式,它打破了许多严格来说并不“合法”但以前工作的用例。坚持文档,您不应该淡出UIVisualEffectView,当您使用UIModalTransitionStyleCrossDissolve 时会发生这种情况。它现在似乎在 iOS 10 上被破坏了,以及视觉效果视图的遮罩等。

    在你的情况下,我建议一个简单的修复,它也将创建比以前更好的效果,并且在 iOS 9 和 10 上都受支持。创建一个自定义演示文稿,而不是淡入视图,动画 effect属性从nil 到模糊效果。如果需要,您可以淡入视图层次结构的其余部分。这将巧妙地为模糊半径设置动画,类似于您拉下主屏幕图标时的样子。

    【讨论】:

    • 太棒了!效果很好。我使用了与我发布的视频相同的项目,并将其与您的解决方案一起上传到 GitHub。谢谢你。 > github.com/Axort/BlurTest-iOS10
    • 我建议使用弹簧动画,持续时间为 0.5。这就是本地人所做的。
    • @Axort 你有那个的 swift 版本吗?
    • 谢谢。它像宣传的那样工作 请注意,您必须首先将视觉效果视图的效果属性设置为 nil。然后你为你的目标“效果”设置动画。 (例如光)。而且您不能设置视觉效果视图或任何超级视图的 alpha。 (在某种程度上,这在 iOS 9 中有效,而在 iOS 10 中则完全无效。)Apple 为您带来的另一个优秀 API。我只能说感谢 Stack Overflow 及其贡献者...
    • @Axort 感谢您的 github 解决方案,完美运行!!
    【解决方案2】:
        UIView.animate(withDuration: 0.5) {
            self.effectView.effect = UIBlurEffect(style: .light)
        }
    

    在 iOS9 和 10 上测试。对我来说很好

    【讨论】:

      【解决方案3】:

      当 ViewController 出现时,下面的代码会模糊父视图控制器。在 iOS9 和 10 上测试。

      @interface ViewController () <UIViewControllerTransitioningDelegate, UIViewControllerAnimatedTransitioning>
      
      @property (nonatomic) UIVisualEffectView *blurView;
      
      @end
      
      
      @implementation ViewController
      
      - (instancetype)init
      {
          self = [super init];
          if (!self)
              return nil;
      
          self.modalPresentationStyle = UIModalPresentationOverCurrentContext;
          self.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
          self.transitioningDelegate = self;
      
          return self;
      }
      
      - (void)viewDidLoad
      {
          [super viewDidLoad];
      
          self.view.backgroundColor = [UIColor clearColor];
          self.blurView = [UIVisualEffectView new];
          [self.view addSubview:self.blurView];
          self.blurView.frame = self.view.bounds;
      }
      
      - (id <UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented
                                                                             presentingController:(UIViewController *)presenting
                                                                         sourceController:(UIViewController *)source
      {
          return self;
      }
      
      -(NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext
      {
          return 0.3;
      }
      
      -(void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
      {
          UIView *container = [transitionContext containerView];
      
          [container addSubview:self.view];
      
          self.blurView.effect = nil;
      
          [UIView animateWithDuration:0.3 animations:^{
              self.blurView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark];
          } completion:^(BOOL finished) {
              [transitionContext completeTransition:finished];
          }];
      }
      
      @end
      

      【讨论】: