我有一个自定义视图控制器,可以包含两个子视图控制器。当设备处于纵向时,其中一个控制器的视图可见。当设备处于横向时,其他控制器的视图可见。但是,当横向方向视图可见时,状态栏将缩回以为特定视图腾出更多空间。设备重新进入纵向模式后,状态栏将取消显示。这是自定义视图控制器显示在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;
}];
}
}
非常感谢任何可以花时间看这个的人。
答案 0 :(得分:2)
很多人似乎都有这个问题,就像我一样,还有其他Q / A线程,你应该搜索它 - 我可能永远找不到神奇的答案。在某些情况下,您可能会尝试“修复”问题的一个问题是当您将条形图可见性更改为(重新)显示状态栏时:
如果您隐藏状态栏,则隐藏,隐藏,取消隐藏。
有时人们发现在取消隐藏导航栏之前需要稍微延迟 - 所以在异步调度块中这样做是为了在下一个runloop上运行。类似的东西:
dispatch_async(dispatch_get_main_queue(), ^{
[self.navigationController setNavigationBarHidden:NO animated:NO];
});
答案 1 :(得分: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.frame
和self.navigationController.navigationBar.frame
以考虑状态栏位置的差异。当我们来自viewDidAppear:
时,我需要输入状态栏高度的负y值,以使子视图正确向上移动。这似乎似乎都很有效。
答案 2 :(得分:0)
状态栏和导航栏重叠隐藏后再次显示,我遇到了同样的问题。我在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;
}
答案 3 :(得分:0)
对于ios7,覆盖prefersStatusBarHidden
- (BOOL)prefersStatusBarHidden {
return NO if landscape and NO if landscape;
}
关于方向更改调用下面的函数来触发prefersStatusBarHidden函数
[self setNeedsStatusBarAppearanceUpdate];
中的详细答案
答案 4 :(得分:0)
这解决了我的问题:
self.automaticallyAdjustsScrollViewInsets = false