【问题标题】:Nice slide transition between non-fullscreen and fullscreen UIViewController非全屏和全屏 UIViewController 之间的漂亮幻灯片过渡
【发布时间】:2011-12-11 12:45:37
【问题描述】:

我有一个不是全屏的视图控制器(有一个状态栏),并且想要呈现一个全屏的模态视图控制器。

如果我在动画开始时隐藏状态栏(父级的 viewWillDisappear 或模态的 viewWillAppear),那么一会儿父级将在没有状态栏的情况下可见,看起来像一个错误。

如果我在动画结束时执行此操作(父级的 viewDidDisappear 或模态的 viewDidAppear),那么状态栏将在模态视图上显示片刻,即它不会显示为模态视图“覆盖它”。

有没有办法很好地做到这一点?

编辑:

一种可能性是至少在动画期间创建一个具有 windowLevel=alert 的 UIWindow。示例 iAd 广告似乎很好地覆盖了状态栏,没有另一个窗口,所以它一定是可能的。

【问题讨论】:

  • 我认为您的 UIWindow 解决方案可能是正确的方法。当我们需要在视图控制器之间进行不寻常的转换时,我们会在我们的应用中使用类似的技术。

标签: ios uiviewcontroller


【解决方案1】:

另一个有趣的小项目。这是我能想到的最好的。如果您不介意使用自己的容器控制器来管理呈现/关闭视图控制器,那还不错。我尝试以一般方式做事,但如果需要,可以将其整合到带有 ContainerViewController 的应用程序中。

请注意,我只实现了 UIModalTransitionStyleCoverVertical 的等效项。您也可以根据自己的喜好自定义动画。

相关动画代码:

- (void)presentViewController:(UIViewController *)viewControllerToPresent
{   
    // do nothing if no controller
    if (!viewControllerToPresent) return;

    [__viewControllers addObject:viewControllerToPresent];
    CGRect toFrame = viewControllerToPresent.view.frame;
    toFrame.origin = CGPointMake(0, CGRectGetMaxY(self.view.bounds));
    viewControllerToPresent.view.frame = toFrame;

    [UIView transitionWithView:self.view
                      duration:0.2
                       options:UIViewAnimationOptionTransitionNone
                    animations:^{
                        [[UIApplication sharedApplication] setStatusBarHidden:viewControllerToPresent.wantsFullScreenLayout withAnimation:UIStatusBarAnimationSlide];
                        [self.view addSubview:viewControllerToPresent.view];
                        viewControllerToPresent.view.frame = [UIScreen mainScreen].applicationFrame;
                    }
                    completion:nil];
}

- (void)dismissViewController
{
    // nothing to dismiss if showing first controller
    if (__viewControllers.count <= 1) return;

    UIViewController *currentViewController = [__viewControllers lastObject];
    UIViewController *previousViewController = [__viewControllers objectAtIndex:__viewControllers.count - 2];

    [UIView transitionWithView:self.view
                      duration:0.2
                       options:UIViewAnimationOptionTransitionNone
                    animations:^{
                        [[UIApplication sharedApplication] setStatusBarHidden:previousViewController.wantsFullScreenLayout withAnimation:UIStatusBarAnimationSlide];
                        CGRect toFrame = currentViewController.view.frame;
                        toFrame.origin = CGPointMake(0, CGRectGetMaxY(self.view.bounds));
                        currentViewController.view.frame = toFrame;
                    }
                    completion:^(BOOL finished) {
                        [currentViewController.view removeFromSuperview];
                        [__viewControllers removeLastObject];
                    }];
}

【讨论】:

    【解决方案2】:

    我使用以下代码在我的应用中执行此操作:

    [[UIApplication sharedApplication] setStatusBarStyle: UIStatusBarStyleBlackOpaque];
    [[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation: UIStatusBarAnimationSlide ];
    
    
    DocumentListViewController * dl = [[DocumentListViewController alloc] initWithNibName:@"DocumentListView" bundle:nil] ;
    UINavigationController * nav = [[UINavigationController alloc] initWithRootViewController:dl];
    [dl release];
    
    // Go to the list of documents...
    [[self.view superview] addSubview:nav.view];
    
    nav.view.alpha = 0.0 ;
    
    [self hideActivityAlert];
    
    [UIView animateWithDuration:1.0 animations:^{
        nav.view.alpha = 1.0; } completion:^(BOOL A){
            [self.view removeFromSuperview];
            [self release];} ];
    

    状态栏会在动画发生时快速呈现。

    您必须确保在隐藏状态栏时第一个视图会填满空间。使用具有适当值的属性 autoresizingMask。

    【讨论】:

    • Gabriel,但如果我理解正确的话,这是一个淡入淡出,而不是幻灯片动画。也许我应该更具体。
    • 好的,现在我明白你想要什么了。您希望模态视图从底部显示标准动画并覆盖状态栏。但我认为这是不可能的,因为状态栏是用于应用程序而不是用于视图。因此,您最多可以做的是,就像在我的代码中一样,在同一动画中隐藏状态栏。然后,当模态视图出现时,该栏会隐藏动画。
    【解决方案3】:

    这是一个似乎可行的解决方案。你可以从我的 TSFullScreenModalViewController 派生出你想要模态呈现的视图控制器,或者你可以直接在视图控制器本身中实现代码。

    @interface TSFullScreenModalViewController : UIViewController
    {
        UIWindow*   _window;
    }
    
    - (void) presentFullScreenModal;
    
    @end
    
    @implementation TSFullScreenModalViewController
    
    - (void) viewDidDisappear:(BOOL)animated
    {
        [super viewDidDisappear: YES];
    
        [_window resignKeyWindow];
        [_window release];
        _window = nil;
    }
    
    - (void) presentFullScreenModal
    {
        UIViewController* rvc = [[UIViewController new] autorelease];
        rvc.view.backgroundColor = [UIColor clearColor];
    
        _window = [[UIWindow alloc] initWithFrame: [UIScreen mainScreen].bounds] ;
        _window.windowLevel = UIWindowLevelStatusBar+1;
        _window.backgroundColor = [UIColor clearColor];
        _window.rootViewController = rvc;
        [_window makeKeyAndVisible];
    
        [UIApplication sharedApplication].statusBarHidden = YES;
        [rvc presentModalViewController: self animated: YES];
        [UIApplication sharedApplication].statusBarHidden = NO;
    }
    
    @end
    

    派生您的模态视图控制器,如下所示:

    @interface MyModalViewController : TSFullScreenModalViewController
    {
    }
    
    - (IBAction) onDismiss:(id)sender;
    
    @end
    

    从另一个视图控制器使用它,像这样:

    - (IBAction) onShowModal:(id)sender
    {
        MyModalViewController* mmvc = [[MyModalViewController new] autorelease];
        [mmvc presentFullScreenModal];
    }
    

    最后,像往常一样关闭视图控制器:

    - (IBAction) onDismiss:(id)sender
    {
        [self dismissModalViewControllerAnimated: YES];
    }
    

    【讨论】:

    • 我已经在我的问题中写过关于 UIWindow 方法的问题,但我不想使用它,因为在状态栏或警报级别设置窗口还有很多其他问题。我已经检查过 iAd 没有使用其他窗口。
    • 因此您的新要求是不要使用位于状态栏上方的窗口。在我花时间找出解决方案之前知道这一点会很高兴。
    • 汤姆,我在您回答前 2 天添加了该内容。
    【解决方案4】:

    可能有点小题大做,但您考虑过吗:

    1. 以编程方式截取带有状态栏的第一个视图的屏幕截图(参见SO question
    2. 创建一个新视图,以全屏显示您刚刚拍摄的图像(使用UIImageinitWithFrame
    3. 隐藏状态栏
    4. 展示模态视图控制器

    然后要关闭模态视图,只需反转步骤即可。

    编辑

    因为您无法截取状态栏的屏幕截图,所以无法解决此问题。

    【讨论】:

    • 不能对状态栏进行截图。 UIGetScreenImage() 曾经这样做,但你不能再这样做了。状态栏是它自己的窗口,你不能得到它的引用,afaik。
    【解决方案5】:

    它可以像使用 performSelector:withDelay 延迟 modalViewController 的呈现一样简单:

    告诉状态栏动画出来,然后以正确的延迟启动模态控制器,使其与状态栏动画重合。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-04-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多