模态 VC 和旋转的自定义背景

Posted

技术标签:

【中文标题】模态 VC 和旋转的自定义背景【英文标题】:A custom background for a modal VC and rotation 【发布时间】:2014-03-24 18:44:34 【问题描述】:

我为 iPad 上的模态视图控制器实现了自定义(模糊)背景。我是这样做的:在展示的 VC 的viewWillShow: 中,我拍摄展示的 VC 视图的快照图像,将其模糊,然后在展示的 VC 顶部添加一个 UIImage 视图。这很好用。

但是,当我在显示模式时旋转设备时,模糊图像与它所代表的视图控制器不同步。图像被拉伸以填满屏幕,但视图控制器不会以相同的方式调整其视图的大小。因此,当模态消失并且模糊消失时,过渡看起来很糟糕。

我尝试在didRotateFromInterfaceOrientation: 中拍摄另一张快照,并替换模糊的图像,但没有奏效。

关于如何解决这个问题的任何建议?

更新:a sample project

我的代码(在模态视图控制器中):

- (void)viewWillAppear:(BOOL)animated 
    [super viewWillAppear:animated];
    [self drawBackgroundBlurView];
    

- (void)drawBackgroundBlurView

    if(_blurModalBackground) 

        [_backgroundBlurView removeFromSuperview];

        CGRect backgroundFrame = self.presentingViewController.view.bounds;

        _backgroundBlurView = [[UIImageView alloc] initWithFrame:backgroundFrame];
        _backgroundBlurView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;

        [_backgroundBlurView setImage:[STSUtils imageByBlurringView:self.presentingViewController.view]];

        [self.presentingViewController.view addSubview:_backgroundBlurView];
    

实用程序代码

+ (UIImage *)imageByBlurringView:(UIView *)view

    UIWindow *window = [[[UIApplication sharedApplication] windows] lastObject];

    BOOL isPortrait = (UIInterfaceOrientationIsPortrait([[UIApplication sharedApplication] statusBarOrientation]));

    CGRect frame;
    if(isPortrait) 
        frame = CGRectMake(view.frame.origin.x, view.frame.origin.y, view.frame.size.height, view.frame.size.width);
    
    else 
        frame = CGRectMake(view.frame.origin.x, view.frame.origin.y, view.frame.size.width, view.frame.size.height);
    

    UIGraphicsBeginImageContextWithOptions(frame.size, NO, window.screen.scale);

    [view drawViewHierarchyInRect:frame afterScreenUpdates:NO];

    // Get the snapshot
    UIImage *snapshotImage = UIGraphicsGetImageFromCurrentImageContext();

    // Apply blur
    UIColor *tintColor = [UIColor colorWithWhite:1.0 alpha:0.3];
    UIImage *blurredSnapshotImage = [snapshotImage applyBlurWithRadius:8
                                                             tintColor:tintColor
                                                 saturationDeltaFactor:1.8
                                                             maskImage:nil];

    UIGraphicsEndImageContext();

    return blurredSnapshotImage;

【问题讨论】:

能否请您发布实际代码。 @MaxK 发布了代码。 为什么要给self.presentingViewController添加子视图?如果我理解正确,您想在模态图中显示 presentingViewController 的模糊图像 - 那么您应该这样做 [self.view addSubView:_backgroundBlurView] @MaxK 我只想更改 iPad 上模态(非全屏)视图的默认外观。默认行为是使背景半透明。我为此添加了一个模糊。模态视图控制器不受影响。模糊图像需要位于模态下方,因此我将其添加到呈现的 VC 中。我希望这是有道理的! 能否请您将图片保存成照片并使用以下代码UIImage *img = [STSUtils imageByBlurringView:self.presentingViewController.view]; UIImageWriteToSavedPhotosAlbum(img, nil, nil, NULL); 并在此处发布。我们需要定位一个错误——无论是截屏还是显示不正确。尝试使用和不使用模态控制器的两种方向。 【参考方案1】:

我编写了一个简单的示例,该示例从presentingViewController 截取屏幕截图并将其设置为背景图像。这是我的模态视图控制器的实现。它运行良好(在viewWillAppear 和正确处理旋转)。能否请您也发布STSUtils 代码?

#import "ScreenshoterViewController.h"

@interface ScreenshoterViewController ()

@property (weak, nonatomic) IBOutlet UIImageView *imageView;

- (IBAction)buttonBackPressed;

@end

@implementation ScreenshoterViewController

- (void)viewWillAppear:(BOOL)animated

    [super viewWillAppear:animated];

    [self updateImage];


- (void)updateImage

    UIGraphicsBeginImageContext(self.view.bounds.size);
    CGContextRef context = UIGraphicsGetCurrentContext();
    [self.presentingViewController.view.layer renderInContext:context];
    UIImage *img = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    self.imageView.image = img;


- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation

    [self updateImage];


- (IBAction)buttonBackPressed 
    [self dismissViewControllerAnimated:YES
                             completion:NULL];

@end

更新

在你的 utils 代码中替换这个

[view drawViewHierarchyInRect:frame afterScreenUpdates:NO];

有了这个

[view drawViewHierarchyInRect:frame afterScreenUpdates:YES];

来自苹果文档:

afterUpdates 一个布尔值,指示快照是否 应在合并最近的更改后呈现。 如果要在视图中呈现快照,请指定值 NO 层次结构的当前状态,可能不包括最近的更改。

所以您截取的屏幕截图不包含视图中的最新更改。

【讨论】:

我想你在这里回答了一个稍微不同的问题 :) 我不打算对演示者 VC 进行快照并在模态 VC 中显示它。我希望用它自己的快照图像覆盖演示者 VC,但模糊。我将尝试绘制图表并将其添加到我的问题中。 对不起,第一次没有得到你想要的。但现在我愿意,会尽力帮助你。 我已经发布了一个示例项目来说明这个问题。尝试(1)打开模态,然后(2)旋转屏幕,(3)然后关闭模态。您会看到 (2) 中的模糊背景与 (3) 中的实际背景不匹配。 为什么这是公认的答案?是否有展示重绘作品的示例项目? 我会将 didRotateFromInterfaceOrientation 替换为 viewWillLayoutSubviews - 效果更好,但仍不能以最佳方式处理旋转。

以上是关于模态 VC 和旋转的自定义背景的主要内容,如果未能解决你的问题,请参考以下文章

IOS:使用模态 ViewController 进行转换

iOS 自定义容器 VC 和需要特定方向的子级

使用自定义转换旋转模态 UIViewController

UIBarButtonItem 和界面旋转的自定义

SwiftUI 中的自定义模态转换

使用自定义模式 UIViewControllerTransitioningDelegate 进行旋转