iOS 7状态栏在iPhone应用程序中恢复到iOS 6默认样式?

吖奇说*_*HUō 291 statusbar ios7

在iOS 7 UIStatusBar中,它的设计方式与视图合并如下:

由TinaTavčar设计的GUI (由TinaTavčar设计的GUI )

  • 这很酷,但是当你在视图的顶部有一些东西时它会使你的视图陷入混乱,并且它会与状态栏重叠.

  • 是否有一个简单的解决方案(例如在info.plist中设置属性)可以改变它的工作方式[不重叠]回到它在iOS6中的状态?

  • 我知道一个更直接的解决方案是self.view.center.x为每个视图控制器提供+ 20个点,但是更改它们会使其他尺寸self.view.center.x变得更大(有不同可能导致自定义segue等问题)并且突然变成一个单调乏味的工作最好避免.

  • 如果有人能为我提供单线解决方案,我真的很高兴.

PS我知道我可以通过做某事来隐藏状态栏

[[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:UIStatusBarAnimationNone];
Run Code Online (Sandbox Code Playgroud)

didFinishLaunchingWithOptions方法中,但这是一个解决方法,一个避免问题的捷径,所以我不认为这是一个真正的解决方案.

jar*_*air 449

这是我写的博客文章的交叉发布,但这是iOS 7上状态栏,导航栏和容器视图控制器的完整纲要:

  1. 无法保留iOS 6样式状态栏布局.状态栏将始终与iOS 7上的应用程序重叠

  2. 不要将状态栏外观与状态栏布局混淆.外观(亮或默认)不会影响状态栏的布局方式(帧/高度/重叠).重要的是要注意系统状态栏不再具有任何背景颜色.当API引用UIStatusBarStyleLightContent时,它们表示清晰背景上的白色文本.UIStatusBarStyleDefault是清晰背景上的黑色文本.

  3. 状态栏外观是根据两个互斥的基本路径之一控制的:您可以以传统方式以编程方式设置它们,或者UIKit将根据UIViewController的一些新属性为您更新外观.后一个选项默认启用.检查应用程序的"基于ViewController的状态栏外观"的plist值,看看你正在使用哪一个.如果将此值设置为YES,则应用程序中的每个顶级视图控制器(标准UIKit容器视图控制器除外)都需要覆盖preferredStatusBarStyle,返回默认样式或浅色样式.如果将plist值编辑为NO,则可以使用熟悉的UIApplication方法管理状态栏外观.

  4. UINavigationController会将其UINavigationBar的高度更改为44点或64点,具体取决于一组相当奇怪且未记录的约束.如果UINavigationController检测到其视图框架的顶部与UIWindow的顶部在视觉上是连续的,那么它将绘制高度为64点的导航栏.如果它的视图顶部与UIWindow的顶部不连续(即使只关闭一个点),那么它以"传统"方式绘制其导航栏,高度为44点.即使在应用程序的视图控制器层次结构中有多个子项,UINavigationController也会执行此逻辑.没有办法阻止这种行为.

  5. 如果您提供的高度仅为44磅(88像素)的自定义导航栏背景图像,并且UINavigationController的视图边界与UIWindow的边界匹配(如#4中所述),则UINavigationController将在帧中绘制您的图像(0,20,320) ,44),在自定义图像上方留下20个不透明的黑色空间.这可能会让你误以为你是一个聪明的开发者绕过了规则#1,但你错了.导航栏仍然是64点高.在幻灯片到显示样式视图层次结构中嵌入UINavigationController使得这一点非常清晰.

  6. 注意UIViewController的容易混淆的edgesForExtendedLayout属性.调整edgesForExtendedLayout在大多数情况下不执行任何操作.UIKit使用此属性的唯一方法是,如果将视图控制器添加到UINavigationController,则UINavigationController使用edgesForExtendedLayout来确定其子视图控制器是否应在导航栏/状态栏区域下可见.在UINavigationController上设置edgesForExtendedLayout本身不会改变UINavigationController是否具有44或64点高导航栏区域.有关该逻辑,请参阅#4.使用工具栏或UITabBarController时,类似的布局逻辑适用于视图的底部.

  7. 如果你想要做的就是阻止你的自定义子视图控制器在UINavigationController内部使用导航栏,那么将edgesForExtendedLayout设置为UIRectEdgeNone(或者至少是一个排除UIRectEdgeTop的掩码).在视图控制器的生命周期中尽早设置此值.

  8. UINavigationController和UITabBarController还将尝试在其子视图层次结构中填充表视图和集合视图的contentInsets.它以类似于#4的状态栏逻辑的方式执行此操作.通过为表视图和集合视图设置automaticAdjustsScrollViewInsets为NO(默认为YES),有一种编程方法可以防止这种情况.这给Whisper和Riposte带来了一些严重的问题,因为我们使用contentInset调整来控制表视图的布局以响应工具栏和键盘的移动.

  9. 重申:没有办法返回iOS 6样式状态栏布局逻辑.为了近似这一点,您必须将应用程序的所有视图控制器移动到距离屏幕顶部偏移20个点的容器视图中,在状态栏后面留下有意黑色视图以模拟旧外观.这是我们最终在Riposte和Whisper中使用的方法.

  10. Apple非常努力地确保你不要尝试#9.他们希望我们重新设计我们的所有应用程序以覆盖状态栏.然而,对于用户体验和技术原因,有许多有说服力的论据,为什么这并不总是一个好主意.您应该为用户做最好的事情而不是简单地遵循平台的奇思妙想.

  • 只是想补充一点,您可以在视图顶部的任何内容中添加约束以附加到顶部布局指南 - 这将在状态栏后面留下一个空白区域(您可以使用您想要的任何颜色填充)但也允许视图自动调整到iOS 6中的正确位置.这样您就不必在代码中手动调整视图的位置. (35认同)
  • 这是一个很棒的解决方案.你已经暴露了我对AutoLayout的无知.更好地继续下去. (4认同)
  • @BreadicalMD我不明白的一个部分是iOS 6上没有-topLayoutGuide,所以这是否意味着你需要在iOS 7和6上使用不同的Auto Layout约束? (2认同)

吖奇说*_*HUō 122

2013年9月19日更新:

通过添加来修复扩展错误 self.window.bounds = CGRectMake(0, 20, self.window.frame.size.width, self.window.frame.size.height);

纠正了NSNotificationCenter声明中的拼写错误


2013年9月12日更新:

纠正UIViewControllerBasedStatusBarAppearanceNO

为屏幕旋转的应用添加了解决方案

添加了一种方法来更改状态栏的背景颜色.


显然,没有办法将iOS7状态栏恢复为在iOS6中的工作方式.

但是,我们总是可以编写一些代码并将状态栏转换为iOS6,这是我能想到的最短路径:

  1. 设置UIViewControllerBasedStatusBarAppearanceNOinfo.plist(要选择停止在视图控制器调整状态栏样式,使我们可以通过使用UIApplicationstatusBarStyle方法设置状态栏的风格.)

  2. 在AppDelegate中application:didFinishLaunchingWithOptions,请致电

    if (NSFoundationVersionNumber > NSFoundationVersionNumber_iOS_6_1) {
        [application setStatusBarStyle:UIStatusBarStyleLightContent];
        self.window.clipsToBounds =YES;
        self.window.frame =  CGRectMake(0,20,self.window.frame.size.width,self.window.frame.size.height-20);
    
        //Added on 19th Sep 2013
        self.window.bounds = CGRectMake(0, 20, self.window.frame.size.width, self.window.frame.size.height);
    }
    return YES;
    
    Run Code Online (Sandbox Code Playgroud)


为了:

  1. 检查它是否是iOS 7.

  2. 将状态栏的内容设置为白色,而不是UIStatusBarStyleDefault.

  3. 避免其框架超出可见边界的子视图显示(对于从顶部向主视图设置动画的视图).

  4. 通过移动和调整应用程序的窗口框架,创建状态栏占用空间的错觉,就像在iOS 6中一样.


对于屏幕旋转的应用,

使用NSNotificationCenter通过添加来检测方向更改

[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(applicationDidChangeStatusBarOrientation:)
name:UIApplicationDidChangeStatusBarOrientationNotification
object:nil];
Run Code Online (Sandbox Code Playgroud)

if (NSFoundationVersionNumber > NSFoundationVersionNumber_iOS_6_1)创造中的AppDelegate的新方法:

- (void)applicationDidChangeStatusBarOrientation:(NSNotification *)notification
{
    int a = [[notification.userInfo objectForKey: UIApplicationStatusBarOrientationUserInfoKey] intValue];
    int w = [[UIScreen mainScreen] bounds].size.width;
    int h = [[UIScreen mainScreen] bounds].size.height;
    switch(a){
        case 4:
            self.window.frame =  CGRectMake(0,20,w,h);
            break;
        case 3:
            self.window.frame =  CGRectMake(-20,0,w-20,h+20);
            break;
        case 2:
            self.window.frame =  CGRectMake(0,-20,w,h);
            break;
        case 1:
           self.window.frame =  CGRectMake(20,0,w-20,h+20);
    }
}
Run Code Online (Sandbox Code Playgroud)

因此,当方向发生变化时,它将触发一个switch语句来检测应用程序的屏幕方向(纵向,颠倒,横向左侧或右侧),并分别更改应用程序的窗口框架以创建iOS 6状态栏错觉.


要更改状态栏的背景颜色:

 @property (retain, nonatomic) UIWindow *background;
Run Code Online (Sandbox Code Playgroud)

在您的类中AppDelegate.h创建background属性并防止ARC释放它.(如果您不使用ARC,则无需执行此操作.)

之后,您只需要在以下位置创建UIWindow if (NSFoundationVersionNumber > NSFoundationVersionNumber_iOS_6_1):

background = [[UIWindow alloc] initWithFrame: CGRectMake(0, 0, self.window.frame.size.width, 20)];
background.backgroundColor =[UIColor redColor];
[background setHidden:NO];
Run Code Online (Sandbox Code Playgroud)

别忘了@synthesize background;以后@implementation AppDelegate!

  • @ArchyHolt:除非我提出模态视图控制器,否则您的简单解决方案对我有用.取消模态视图控制器后,剩余视图现在位于状态栏下.我在一个新的示例项目中重现了这一点,以确保没有其他任何时髦的事情发生.我想也许你的更高级的解决方案在这里很有用,但不确定会发出什么通知.有任何想法吗? (4认同)
  • 在关闭模态视图控制器后,视图会重置.:( (4认同)
  • 这打破了轮换.只是一个抬头 (3认同)
  • @JesseNaugher我建议以编程方式将Vertical Spacing Constraint从0修改为20.它将适用于轮换. (2认同)
  • 关于如何避免导航栏扩展20像素的任何想法?这个解决方案对我来说很好,但我的导航栏太高了20像素. (2认同)
  • @markdorison别担心.我已经调查了它并通过添加`self.window.bounds = CGRectMake(0,20,self.window.frame.size.width,self.window.frame.size.height)修复了这个bug;`之后if语句中的`self.window.frame = ...`. (2认同)
  • 当你看到像'UIApplicationDidChangeStatusBarOrientationNotification这样的名字时,你知道API很糟糕 (2认同)

İbr*_*lük 41

更新(新解决方案)

此更新是iOS 7导航栏问题的最佳解决方案.您可以设置导航栏颜色示例:FakeNavBar.backgroundColor = [UIColor redColor];

注意:如果您使用默认导航控制器,请使用旧解决方案.

AppDelegate.m

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{

    if(NSFoundationVersionNumber >= NSFoundationVersionNumber_iOS_7_0)
    {
        UIView *FakeNavBar = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 20)];
        FakeNavBar.backgroundColor = [UIColor whiteColor];

        float navBarHeight = 20.0;
        for (UIView *subView in self.window.subviews) {

            if ([subView isKindOfClass:[UIScrollView class]]) {
                subView.frame = CGRectMake(subView.frame.origin.x, subView.frame.origin.y + navBarHeight, subView.frame.size.width, subView.frame.size.height - navBarHeight);
            } else {
                subView.frame = CGRectMake(subView.frame.origin.x, subView.frame.origin.y + navBarHeight, subView.frame.size.width, subView.frame.size.height);
            }
        }
        [self.window addSubview:FakeNavBar];
    }

    return YES;

}
Run Code Online (Sandbox Code Playgroud)

旧解决方案 - 如果您使用以前的代码,请忽略以下代码和图像

这是旧版iOS 7导航栏解决方案.

我用以下代码解决了这个问题.这是为了添加状态栏.didFinishLaunchingWithOptions

if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0) {
    UIView *addStatusBar = [[UIView alloc] init];
    addStatusBar.frame = CGRectMake(0, 0, 320, 20);
    addStatusBar.backgroundColor = [UIColor colorWithRed:0.973 green:0.973 blue:0.973 alpha:1]; //change this to match your navigation bar
    [self.window.rootViewController.view addSubview:addStatusBar];
}
Run Code Online (Sandbox Code Playgroud)

对于Interface Builder,这适用于使用iOS 6打开的情况; 它从0像素开始.

注意:仅当您在详细信息窗格中的"文件检查器"(最左侧图标)中取消选中"使用Autolayout"视图控制器时,才会显示iOS 6/7 Deltas.

在此输入图像描述

  • 你结束了我的一天.获得+1的帮助! (6认同)
  • 请注意:仅当您在详细信息窗格中的"文件检查器"(最左侧图标)中取消选中"使用Autolayout"视图控制器时,才会显示iOS 6/7 Deltas. (5认同)
  • 谁说iOS 6风格的状态栏布局无法维护,你可以通过@TacettinÖzbölük的方式做到这一点...感谢这个awsum解决方案的伴侣. (2认同)

小智 26

解决方案

通过重写方法在viewcontroller或rootviewcontroller中设置它:

-(BOOL) prefersStatusBarHidden
    {
        return YES;
    }
Run Code Online (Sandbox Code Playgroud)


svr*_*vrs 17

这是另一种广泛使用Storyboard的项目方法:

目标:

这种方法的目标是在iOS7中重新创建与iOS6中相同的状态栏样式(请参阅问题标题"iOS 7 Status Bar返回iOS 6样式?").

摘要:

为了实现这一点,我们通过将状态栏(在iOS 7下)重叠的UI元素向下移动,同时使用增量来恢复iOS 6.1或更早版本的向下布局更改,尽可能多地使用Storyboard.然后,iOS 7中产生的额外空间被UIView占用,backgroundColor设置为我们选择的颜色.后者可以在代码中创建或使用Storyboard创建(参见下面的替代方案)

假设:

为了在按照以下步骤获得所需结果时,假设View controller-based status bar appearance设置为NO并且您Status bar style要么设置为"透明黑色样式(alpha of 0.5)"或"不透明黑色样式".可以在项目设置中的"信息"下找到/或添加这两个设置.

脚步:

  • 将子视图添加到UIWindow以充当状态栏背景.为此,请在AppDelegate application: didFinishLaunchingWithOptions:之后添加以下内容makeKeyAndVisible

    if (NSFoundationVersionNumber > NSFoundationVersionNumber_iOS_6_1) {
        UIView *statusBarBackgroundView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, yourAppsUIWindow.frame.size.width, 20)];
        statusBarBackgroundView.backgroundColor = [UIColor blackColor];
        [yourAppsUIWindow addSubview:statusBarBackgroundView];
    }
    
    Run Code Online (Sandbox Code Playgroud)
  • 由于您仅以编程方式为iOS 7添加了背景,因此您必须相应地调整与状态栏重叠的UI元素的布局,同时保留其iOS6的布局.要实现此目的,请执行以下操作:

    • 确保Use Autolayout您的Storyboard未选中(这是因为"尺寸检查器"中未显示"iOS 6/7 Deltas").去做这个:
      • 选择您的Storyboard文件
      • 显示实用程序
      • 选择"显示文件检查器"
      • 在"Interface Builder Document"下,取消选中"Use Autolayout"
    • 或者,为了帮助您在应用iOS 7和6时监视iOS 7和6的布局更改,请选择"助理编辑器",选择"预览"和"iOS 6.1或更早版本": 在此输入图像描述 在此输入图像描述
    • 现在选择要调整的UI元素,使其不再与状态栏重叠
    • 在Utilities列中选择"Show the Size Inspector"
    • 沿Y轴重新定位UI元素的量与状态栏bg高度相同: 在此输入图像描述
    • 并将Y的iOS6/7 Deltas值更改为与状态栏bg高度相同的负值(如果您正在使用它,请注意iOS 6预览中的更改): 在此输入图像描述

备择方案:

要在故事板大量项目中添加更少的代码并使状态栏背景自动旋转,而不是以编程方式为状态栏添加背景,您可以为位于所述viewcontroller主视图顶部的每个视图控制器添加彩色视图.然后,您可以将此新视图的高度增量更改为与视图高度相同的负数(以使其在iOS 6下消失).

这个替代方案的缺点(尽管考虑到自动旋转兼容性可能可以忽略不计),如果你正在查看iOS 6的故事板,这个额外的视图不会立即可见.你只会知道它在那里,如果你看看"故事板的"文档大纲".


nvr*_*rst 12

如果您不希望视图控制器与状态栏(和导航栏)重叠,请取消选中Xcode 5 中Interface Builder中的"在顶部栏下扩展边缘"框.

取消选中顶栏下的延伸边

  • 只有在使用故事板时才可以这样做 (7认同)
  • 它仅适用于容器vcs,例如导航控制器或tabbar控制器 (3认同)
  • edgesForExtendedLayout仅由容器视图控制器(如UINavigationController)使用,以确定其子视图是否应与父级的chrome重叠.在UIWindow的根视图控制器上设置此属性不会执行任何操作.请参阅上面的答案:http://stackoverflow.com/questions/18294872/ios-7-status-bar-back-to-ios-6-style/18855464#18855464 (2认同)

Igo*_*gor 11

Apple发布了技术问答QA1797:防止状态栏覆盖您的观点.它适用于iOS 6和iOS 7版本.

  • Apple假设每个人都在使用自动布局.Xcode 4中的自动布局非常糟糕,Xcode 5刚刚发布,所以这是一个可疑的假设. (5认同)

fir*_*oke 8

我已经查看了许多很多很多教程来解决这个问题.但它们都不起作用!这是我的解决方案,它适用于我:

if( [[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0f ) {
    float statusBarHeight = [[UIApplication sharedApplication] statusBarFrame].size.height;
    for( UIView *v in [self.view subviews] ) {
        CGRect rect = v.frame;
        rect.origin.y += statusBarHeight;
        v.frame = rect;
    }
}
Run Code Online (Sandbox Code Playgroud)

逻辑很简单.我将所有孩子的观点转移到了20个像素的self.view上.就这样.然后,屏幕截图将像iOS 6一样显示.我讨厌iOS7状态栏!〜"〜

  • 我应该在哪里添加这个?在应用程序委托确实推出了选项? (2认同)

Cœu*_*œur 6

Archy Holt答案的一个小替代品,更简单一点:

一个.设置UIViewControllerBasedStatusBarAppearanceNOinfo.plist

湾 在AppDelegate,s application:didFinishLaunchingWithOptions:,致电:

if ([[UIDevice currentDevice].systemVersion floatValue] < 7)
{
    self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
}
else
{
    // handling statusBar (iOS7)
    application.statusBarStyle = UIStatusBarStyleLightContent;
    self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].applicationFrame];
    self.window.clipsToBounds = YES;

    // handling screen rotations for statusBar (iOS7)
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationDidChangeStatusBarOrientationNotification:) name:UIApplicationDidChangeStatusBarOrientationNotification object:nil];
}
Run Code Online (Sandbox Code Playgroud)

并添加方法:

- (void)applicationDidChangeStatusBarOrientationNotification:(NSNotification *)notification
{
    // handling statusBar (iOS7)
    self.window.frame = [UIScreen mainScreen].applicationFrame;
}
Run Code Online (Sandbox Code Playgroud)

您还可以考虑子类化UIWindow来处理UIApplicationDidChangeStatusBarOrientationNotification自身.


Ign*_*ers 5

我在所有的视图控制器中使用它,这很简单.在所有viewDidLoad方法中添加以下行:

- (void)viewDidLoad{
    //add this 2 lines:
    if ([self respondsToSelector:@selector(edgesForExtendedLayout)])
        self.edgesForExtendedLayout = UIRectEdgeNone;

    [super viewDidLoad];
}
Run Code Online (Sandbox Code Playgroud)