4

我有一个可以包含两个子视图控制器的自定义视图控制器。当设备处于纵向时,可以看到其中一个控制器的视图。当设备处于横向时,另一个控制器的视图可见。但是,当横向视图可见时,状态栏会缩回,以便为特定视图腾出更多空间。设备转回纵向模式后,状态栏将取消隐藏。这是自定义视图控制器显示在UINavigationController.

我的问题是当状态栏的可见性发生变化时,我的子视图没有正确调整。当您以不同的方向转动设备时,最终会出现很大的间隙和/或重叠,如下图所示: 在此处输入图像描述

如您所见,它最初很好(纵向),但是当设备转动时,状态栏所在的位置有一个白色间隙。当设备转回纵向时,UINavigationController会弹出导航栏并与状态栏重叠,并且导航栏与其下方的视图之间会出现间隙。如果您非常快速地从一个横向旋转 180 度到相反的横向,间隙就会消失并且看起来不错。

下面的方法属于自定义视图控制器,被调用willAnimateRotationToInterfaceOrientation:duration:(显然是为了处理旋转事件)和viewDidAppear:(当视图从导航堆栈中的前一个视图控制器推入时进行处理)。

- (void)cueAnimationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation fromViewDidAppear:(BOOL) fromViewDidAppear
{
    // Fading animation during orientation flip.
    // Make sure its not already animating before trying.
    BOOL barHidden =  [UIApplication sharedApplication].statusBarHidden;
    if (!isAnimating) {
        BOOL alreadyGoodGrid = (UIInterfaceOrientationIsLandscape(interfaceOrientation) && curView == self.gridViewController.view);
        BOOL alreadyGoodTable = (UIInterfaceOrientationIsPortrait(interfaceOrientation) && curView == self.tableViewController.view);
        if ((alreadyGoodGrid && barHidden) ||
            (alreadyGoodTable && !barHidden)) {
            // If views are the way they should be for this orientation. Don't do
            // anything.
            return;
        }
        isAnimating = YES;
        UIView *nextView;
        // Get starting orientation. This will determine what view goes on top
        if (UIInterfaceOrientationIsLandscape(interfaceOrientation))
            nextView = self.gridViewController.view;
        else
            nextView = self.tableViewController.view;

        if (nextView == self.tableViewController.view)
        {
            if (!alreadyGoodTable)
            {
                self.tableViewController.view.alpha = 0.0;
                [self.view bringSubviewToFront:self.tableViewController.view];
            }
            // Unhide the bar for the table view
            [[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationSlide];
        }
        else // gridViewController
        {
            if (!alreadyGoodGrid)
            {
                self.gridViewController.view.alpha = 0.0;
                [self.view bringSubviewToFront:self.gridViewController.view];
            }
            // Hide the bar for the grid view
            [[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:UIStatusBarAnimationSlide];
        }
        [UIView animateWithDuration:0.4
                              delay: 0.0
                            options: UIViewAnimationOptionAllowUserInteraction
                         animations:^{
                             if (nextView == self.tableViewController.view) {
                                 self.tableViewController.view.alpha = 1.0;
                             }
                             else {
                                 self.gridViewController.view.alpha = 1.0;
                             }                             
                         }
                         completion:^(BOOL finished) {
                             if (nextView == self.tableViewController.view) {
                                 curView = self.tableViewController.view;
                             }
                             else {
                                 curView = self.gridViewController.view;
                             }
                             isAnimating = NO;
                         }];
    }
}

非常感谢任何可以花时间看这个的人。

4

5 回答 5

2

很多人似乎都有这个问题,就像我一样,还有其他关于它的 Q/A 线程你应该搜索——我可能永远找不到神奇的答案。在某些情况下,您可能会尝试一种似乎“解决”问题的方法,即当您将栏可见性更改为(重新)显示状态栏时:

  • 隐藏导航栏。
  • 取消隐藏状态栏。
  • 取消隐藏导航栏。

或者,如果您要隐藏状态栏,则隐藏、隐藏、取消隐藏。

有时人们发现在取消隐藏导航栏之前需要稍微延迟 - 所以在异步调度块中执行此操作以在下一个运行循环中运行。就像是:

dispatch_async(dispatch_get_main_queue(), ^{
        [self.navigationController setNavigationBarHidden:NO animated:NO];
});
于 2013-03-03T21:37:20.170 回答
0

对于 ios7,覆盖 prefersStatusBarHidden

- (BOOL)prefersStatusBarHidden {
    return NO if landscape and NO if landscape;
}

在方向改变时调用下面的函数来触发 prefersStatusBarHidden 函数

[self setNeedsStatusBarAppearanceUpdate];

请参阅https://stackoverflow.com/a/19194901/1939554中的详细答案

于 2014-07-28T13:21:16.423 回答
0

在摆弄了很多之后,我似乎想出了某种解决方案。它似乎可以正常工作。

这是我的代码:

- (void)cueAnimationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation fromViewDidAppear:(BOOL) fromViewDidAppear
{
    // Fading animation during orientation flip.
    // Make sure its not already animating before trying.
    BOOL barHidden =  [UIApplication sharedApplication].statusBarHidden;
    if (!isAnimating) {
        BOOL alreadyGoodGrid = (UIInterfaceOrientationIsLandscape(interfaceOrientation) && curView == self.gridViewController.view);
        BOOL alreadyGoodTable = (UIInterfaceOrientationIsPortrait(interfaceOrientation) && curView == self.tableViewController.view);
        if ((alreadyGoodGrid && barHidden) ||
            (alreadyGoodTable && !barHidden)) {
            // If views are the way they should be for this orientation. Don't do
            // anything.
            return;
        }
        isAnimating = YES;
        UIView *nextView;
        // Get starting orientation. This will determine what view goes on top
        if (UIInterfaceOrientationIsLandscape(interfaceOrientation))
            nextView = self.gridViewController.view;
        else
            nextView = self.tableViewController.view;

        if (nextView == self.tableViewController.view)
        {
            if (!alreadyGoodTable)
            {
                self.tableViewController.view.alpha = 0.0;
                [self.view bringSubviewToFront:self.tableViewController.view];
            }
            [[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationSlide];
        }
        else
        {
            if (!alreadyGoodGrid)
            {
                self.gridViewController.view.alpha = 0.0;
                [self.view bringSubviewToFront:self.gridViewController.view];
            }
            [[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:UIStatusBarAnimationSlide];
        }
        [UIView animateWithDuration:0.4
                              delay: 0.0
                            options: UIViewAnimationOptionAllowUserInteraction
                         animations:^{
                             CGRect r = self.navigationController.navigationBar.frame;
                             if (nextView == self.tableViewController.view) {
                                 self.tableViewController.view.alpha = 1.0;
                                 self.navigationController.navigationBar.frame = CGRectMake(0.0, 20.0, r.size.width, r.size.height);
                                 self.view.frame = CGRectMake(0.0, 20.0, self.view.frame.size.width, self.view.frame.size.height - 20.0);

                             }
                             else {
                                 self.gridViewController.view.alpha = 1.0;
                                 self.navigationController.navigationBar.frame = CGRectMake(0.0, 0.0, r.size.width, r.size.height);
                                 double y = 0.0, h = 0.0;
                                 if (fromViewDidAppear)
                                 {
                                     y = -20.0;
                                     h = 20.0;
                                 }
                                 self.view.frame = CGRectMake(0.0, y, self.view.frame.size.width, self.view.frame.size.height + h);
                             }                             
                         }
                         completion:^(BOOL finished) {
                             if (nextView == self.tableViewController.view) {
                                 curView = self.tableViewController.view;
                             }
                             else {
                                 curView = self.gridViewController.view;
                             }
                             isAnimating = NO;
                         }];
    }
}

我所做的是检查该方法是从其他地方调用viewDidAppear:还是从其他地方调用(仅在这种情况下willAnimateRotationToInterfaceOrientation:duration:)。根据谁调用该方法,事情的行为会有所不同。无论哪种情况,我都会调整self.view.frameself.navigationController.navigationBar.frame考虑状态栏位置的差异。当我们来自时,viewDidAppear:我需要输入状态栏高度的负 y 值,以使子视图正确向上移动。这似乎一切都很好。

于 2013-03-04T03:39:53.110 回答
0

这解决了我的问题:

self.automaticallyAdjustsScrollViewInsets = false
于 2014-11-29T01:21:01.217 回答
0

状态栏和导航栏在隐藏然后再次显示后重叠,我遇到了同样的问题。我在 github 上找到了一个解决方案请参阅showUI方法),我对其进行了修改以满足我的需要。

- (void)toggleNavBar:(BOOL)hide
{    
    navBarHidden = hide;

    //Fade status bar
    [[UIApplication sharedApplication] setStatusBarHidden:hide 
                                            withAnimation:UIStatusBarAnimationFade];

    //Fade navigation bar
    [UINavigationBar beginAnimations:nil context:nil];
    [UIView setAnimationDuration:0.3]; // Approximately the same time the status bar takes to fade.

    self.navigationController.navigationBar.alpha = hide ? 0 : 1;

    [UINavigationBar commitAnimations];

    // Being invisible messes with the position of the navigation bar, every time it gets 
    // visible we need to set it to the correct y-offset (just below the status bar)
    [self adjustNavBarOrigin];
}

-(void)adjustNavBarOrigin
{
    CGRect r = self.navigationController.navigationBar.frame;
    r.origin.y = 20; //Height of the statusbar, can't find a reliable method in the SDK to get this value
    self.navigationController.navigationBar.frame = r;   
}
于 2013-05-27T06:32:33.037 回答