iOS隐藏和取消隐藏状态栏未正确移动子视图

iOS隐藏和取消隐藏状态栏未正确移动子视图,ios,user-interface,statusbar,uiinterfaceorientation,Ios,User Interface,Statusbar,Uiinterfaceorientation,我有一个自定义视图控制器,可以包含两个子视图控制器。当设备处于纵向时,其中一个控制器的视图可见。当设备处于横向时,另一个控制器的视图可见。但是,当横向视图可见时,状态栏会缩回,以便为特定视图留出更多空间。设备返回纵向模式后,状态栏将取消隐藏。这是自定义视图控制器,显示在UINavigationController中 我的问题是,当状态栏的可见性更改时,我的子视图没有正确调整。当您以下图所示的不同方向转动设备时,会出现较大的间隙和/或重叠: 正如您所看到的,它最初很好(在纵向),但当设备转动时,

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

我的问题是,当状态栏的可见性更改时,我的子视图没有正确调整。当您以下图所示的不同方向转动设备时,会出现较大的间隙和/或重叠:

正如您所看到的,它最初很好(在纵向),但当设备转动时,状态栏所在的位置有一个白色的间隙。当设备返回到纵向时,
UINavigationController
的导航栏将被状态栏打开并重叠,导航栏与下方视图之间出现间隙。如果您很快地从一个横向方向旋转180度到另一个横向方向,则间隙会消失,看起来很好

下面的方法属于自定义视图控制器,在
WillAnimateRotationInterfaceOrientation:duration:
(显然是为了处理旋转事件)和
视图显示:
(为了处理从导航堆栈中的上一个视图控制器中推入的视图)


非常感谢所有能抽出时间来研究这个问题的人。

很多人似乎都有这个问题,就像我一样,还有其他的问答线索,你应该去寻找——我可能永远也找不到神奇的答案。在某些情况下,您可能会尝试一个看似“修复”问题的难题,即当您将状态栏的可见性更改为(重新)显示状态栏时:

  • 隐藏导航栏
  • 取消隐藏状态栏
  • 取消隐藏导航栏
或者隐藏、隐藏、取消隐藏状态栏

有时人们会发现,在取消隐藏导航条之前需要稍微延迟—所以在异步调度块中这样做,以便在下一个runloop上运行。比如:

dispatch_async(dispatch_get_main_queue(), ^{
        [self.navigationController setNavigationBarHidden:NO animated:NO];
});

在反复摆弄之后,我似乎想出了某种解决办法。它似乎没有失败

这是我的密码:

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

我要做的是检查该方法是从
viewdide:
还是从其他地方调用的(在本例中,仅
willanimaterotationInterfaceOrientation:duration:
)。根据调用方法的人的不同,情况会有所不同。在这两种情况下,我都会调整
self.view.frame
self.navigationController.navigationBar.frame
,以说明状态栏位置的差异。当我们从
视图查看时,显示:
我需要输入状态栏高度的负y值,以使子视图正确向上移动。这一切似乎都运行得相当好。

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

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

对于ios7,重写prefersStatusBarHidden

- (BOOL)prefersStatusBarHidden {
    return NO if landscape and NO if landscape;
}
更改方向时,调用下面的函数以触发prefersStatusBarHidden函数

[self setNeedsStatusBarAppearanceUpdate];

请参阅

中的详细答案,这解决了我的问题:

self.automaticallyAdjustsScrollViewInsets = false

谢谢你的帮助。投你一票。我最终找到了另一个似乎很有效的解决方案,我只是将其作为一个答案发布。很高兴你找到了一些东西——也许它会帮助我!你能在回答中解释一下为什么它解决了你的问题吗?我的问题是,当我试图在包含子视图的视图中隐藏导航/状态栏时,子视图会随着顶部栏移动。最近我发现问题在于插入设置。
self.automaticallyAdjustsScrollViewInsets = false