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

问题描述:

我有一个可以包含两个子视图控制器的自定义视图控制器。当设备处于纵向方向时,其中一个控制器的视图变得可见。当设备处于横向方向时,其他控制器的视图变为可见。然而,当横向取向视图可见时,状态栏会缩回以为特定视图留出更多空间。设备重新转换为纵向模式后,状态栏不显示。这是自定义视图控制器显示在UINavigationController内。iOS隐藏和取消隐藏状态栏没有正确移动子视图

我的问题是,当状态栏的可见性变化时,我的子视图不能正确调整。有最终被一个大的间隙和/或重叠,当开启设备在不同的取向,如下图所示: enter image description here

正如你可以看到,它最初是细(纵向),但是当该装置被关,状态栏是白色的空白处。当设备转回肖像时,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; 
         }]; 
    } 
} 

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

很多人似乎都有这个问题,因为我有,而且还有其他有关它的Q/A线索,你应该寻找 - 我可能永远找不到神奇的答案。在某些情况下,您可能会试图解决问题的一种方法是在将条形可见性更改为(重新)显示状态条时:

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

或隐藏,隐藏,取消隐藏如果你隐藏状态栏。

有时候人们发现在隐藏导航栏之前需要略微延迟 - 所以在异步调度块中在下一个runloop上运行。例如:

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

感谢您的帮助。对你有好处。我确实得到了另一个解决方案,似乎很好,我只是作为答案发布。 – 2013-03-04 03:40:57

+0

很高兴你找到了一些东西 - 也许它会帮助我! – 2013-03-04 16:12:46

在摆弄了很多东西之后,我似乎想出了一些解决方案。它似乎工作没有失败。

这里是我的代码:

- (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值,以使子视图正常向上移动。这似乎都似乎工作得很好。

我在隐藏状态栏和导航栏重叠后出现同样的问题,然后再次显示。我在github here(见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; 
} 

为ios7,覆盖prefersStatusBarHidden

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

的方向变化调用函数低于触发prefersStatusBarHidden功能

[self setNeedsStatusBarAppearanceUpdate]; 

看到https://stackoverflow.com/a/19194901/1939554

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

self.automaticallyAdjustsScrollViewInsets = false 
+0

你能否在你的回答中解释为什么它解决了你的问题? – Zulu 2014-11-29 01:27:38

+0

我的问题是,当我试图在包含子视图的视图中隐藏导航/状态栏时,子视图将随顶部栏移动。最近我发现问题与插入设置。 – 2014-11-29 01:47:41