当状态栏被隐藏/显示时,向上/向下滑动所有视图

时间:2012-06-24 17:57:53

标签: objective-c ios autoresizingmask uistatusbar

我让用户随意显示/隐藏statusBar,我希望所有视图都可以向下滑动/向上滑动。我假设设置自动调整掩码会处理这个问题。我已经以编程方式添加了导航控制器,所以我这样做了:

[self.view setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
[self.navigationController.view setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
[self.navigationController.navigationBar setAutoresizingMask:UIViewAutoresizingFlexibleTopMargin];

这没有效果。

我在隐藏statusBar之前和之后打印了self.viewself.navigationController.view的框架,并且它们保持完全相同的高度。

由于autoresizesSubviews默认为YES,我怀疑这是问题所在。我不能正确设置自动调整遮罩。有人知道我做错了吗?

1 个答案:

答案 0 :(得分:0)

答案似乎是容器视图的自动调整掩码根本不与状态栏协调。除了编写调整布局的代码之外别无选择。

由于Apple没有提供statusBar和其他元素之间的自动协调,你认为他们会让我们自己做。但是,不,我们不允许直接设置statusBar框架。动画statusBar重新定位动画的唯一方法是通过UIStatusBarAnimationSlide,它使用自己的时间轴,永远不会匹配其他动画。

但是,我们可以控制statusBar淡入淡出的时间并随之滑动容器视图。子视图' autoresize mask将完成剩下的工作。这实际上看起来很不错,编码虽然因一些奇怪的框架行为而变得复杂,但并不太痛苦:

UIApplication *appShared = [UIApplication sharedApplication];
CGFloat fStatusBarHeight = appShared.statusBarFrame.size.height; // best to get this once and store it as a property
BOOL bHideStatusBarNow = !appShared.statusBarHidden;
CGFloat fStatusBarHeight = appDelegate.fStatusBarHeight;
if (bHideStatusBarNow)
    fStatusBarHeight *= -1;

CGRect rectView = self.view.frame; // must work with frame; changing the bounds won't have any effect

// Determine the container view's new frame.
// (The subviews will autoresize.)
switch (self.interfaceOrientation) {
    case UIInterfaceOrientationPortrait:
    case UIInterfaceOrientationPortraitUpsideDown: 
        rectView.origin.y += fStatusBarHeight;
        rectView.size.height -= fStatusBarHeight;
        break;
    case UIInterfaceOrientationLandscapeLeft:
    case UIInterfaceOrientationLandscapeRight:
        // In landscape, the view's frame will sometimes complement the orientation and sometimes not. 
        /*
         Specifically, if view is loaded in landscape, its frame will reflect that; otherwise, the frame will always be in portrait orientation.
         This is an issue only when the navBar is present. Regular view controllers can count on the frame staying in portrait orientation no matter what.
         But regular view controllers have another oddity: In the upside-down orientations, you should adjust the height only; the origin takes care of itself.
         */
        if (rectView.size.width < rectView.size.height) {
            rectView.origin.x += fStatusBarHeight;
            rectView.size.width -= fStatusBarHeight;
        }
        else {
            rectView.origin.y += fStatusBarHeight;
            rectView.size.height -= fStatusBarHeight;
        }
        break;
    default:
        break;
}

// The navBar must also be explicitly moved.
CGRect rectNavBar = [self.navigationController.navigationBar frame];
rectNavBar.origin = CGPointMake(0.0f, rectNavBar.origin.y + fStatusBarHeight);

// Perform the animated toggling and reframing.
[UIView animateWithDuration:kAnimDurationToggleStatusBar animations:^{
    [appShared setStatusBarHidden:bHideStatusBarNow]; // you can add withAnimation:UIStatusBarAnimationSlide here and it will work, but the timing won't match
    [self.navigationController.navigationBar setFrame:rectNavBar];
    [self.view setFrame:rectView];
}];

只要你有将窗口框架设置为mainScreen.bounds,就不需要对工具栏做任何事情,它仍然粘在屏幕的底部。

一个障碍是当你想重新显示它时如何获得statusBar高度,因为statusBarFrame返回一个0区域的矩形,如果它当前是隐藏的。事实证明,做一个初步显示/隐藏,没有动画,只是为了得到矩形,工作正常。没有可见的闪光灯。

另外,如果您使用的是xib / nib,请确保其视图的statusBar设置为None。

也许有一天Apple会增强statusBar布局行为。然后,对于每个视图控制器,所有这些代码都必须重做...