iOS7中状态栏和导航栏问题

58

我正在将我的应用迁移到iOS 7。为了处理状态栏问题,我已经添加了这段代码

if([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0f)
{
    CGRect frame = self.navigationController.view.frame;
    if(UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
    {
        frame.origin.y = 20;
    }
    else
    {
        frame.origin.x = 20;
    }
    [self.navigationController.view setFrame:frame];
}

这在正常情况下工作得很好。如果我改变方向(应用程序仅支持横向方向)或呈现任何视图控制器并解除模态视图控制器,我的视图控制器对齐方式会发生变化。状态栏再次重叠在我的视图控制器上。这段代码根本不起作用。请指导我修复这个状态栏问题。

情况2:这是我呈现我的视图控制器的方法

ZBarReaderViewController *reader = [ZBarReaderViewController new];
reader.readerDelegate = self;
    
if(UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
    reader.supportedOrientationsMask = ZBarOrientationMaskLandscape;
else
    reader.supportedOrientationsMask = ZBarOrientationMaskPortrait;
    
    [self presentModalViewController:reader animated:YES];

参考:

这里输入图片描述


正如我之前提到的,如果屏幕方向改变,则状态栏重叠问题会发生,不仅限于 presentmodelviewcontroller 情况。 - Ganapathy
1
这是一个直截了当的答案:https://dev59.com/WGMl5IYBdhLWcg3wAC2h - aryaxt
11个回答

133

iOS 7状态栏问题的修复方法

最终,我使用xcode5中的delta值属性解决了状态栏重叠问题。首先,我将Xib中所有控制器的原点-y增加20像素(在iOS 7中似乎只能正常工作),然后对所有视图控制器的原点-y设置了-20的delta值,这可以在iOS 6和iOS 7中正常工作。

做法如下:

Xcode 5提供预览选项以查看不同操作系统版本下xib外观的预览。

从助理编辑器中选择预览选项

单击助理编辑器

enter image description here

并选择预览选项以预览不同版本的选定视图控制器。

enter image description here

预览选项。

enter image description here

在预览中,您可以找到切换选项以在不同版本中预览视图。如果未正确修复状态栏问题,则可以通过切换版本来清楚地感受到它。

修复状态栏问题的三个步骤: 步骤1:确保在文件检查器中,视图目标是7.0及更高版本

enter image description here

步骤2:增加所有添加到视图控制器中的控件的原点-y值20像素(正好为状态栏的大小)。

步骤3:设置所有控件的原点y的delta值为-20,然后它将根据版本自动调整。现在使用预览功能,您会发现控件由于delta值而自动调整大小。

enter image description here

一旦状态栏问题得到解决,呈现模型视图时(ZbarSDk控制器)的问题也会自动解决。

预览屏幕:

enter image description here


10
如果您对我的回答不满意,可以留下评论,让我可以改进我的回答。谁给了我负1分的评价请不要回复。 - Ganapathy
1
如果您以编程方式添加了控件,则需要将所有已添加的控件(以编程方式添加的)的原点y增加到20,如果设备版本大约为7.0。 - Ganapathy
2
当我按照您的步骤进行时,我无法像您在#step2中提到的那样将我的视图位置设置为+20,因为它被禁用了。我该如何使其可编辑? - ASHISHT
嗨@Ganapathy,我想知道预览选项在哪里? - Vigor
3
神啊,iOS 的布局系统看起来很混乱。硬编码、版本相关的偏移量?这是认真的吗,苹果? - me--
显示剩余13条评论

15

我回答晚了,但我想分享一下我所做的事情,这基本上是最简单的解决方案。

首先,打开info.plist文件,将状态栏样式添加为透明黑色风格(透明度为0.5)

现在,开始操作:

在AppDelegate.m中添加此代码

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
    {
     //Whatever your code goes here
  if(kDeviceiPad){

     //adding status bar for IOS7 ipad
         if (IS_IOS7) {
              UIView *addStatusBar = [[UIView alloc] init];
              addStatusBar.frame = CGRectMake(0, 0, 1024, 20);
              addStatusBar.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:1]; //change this to match your navigation bar
              [self.window.rootViewController.view addSubview:addStatusBar];
                    }
                }
    else{

         //adding status bar for IOS7 iphone
        if (IS_IOS7) {
            UIView *addStatusBar = [[UIView alloc] init];
            addStatusBar.frame = CGRectMake(0, 0, 320, 20);
            addStatusBar.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:1]; //You can give your own color pattern
            [self.window.rootViewController.view addSubview:addStatusBar];
        }

    return YES;
   }

非常简单。您可以在前4行中了解到这一点。有关详细说明,我已添加屏幕快照。我已经搜索了一个多小时,但没有人建议将子视图添加到根视图控制器中以解决此问题。最好在编程时处理框架,以防止不必要地添加子视图。就是这样。 - Ganapathy
根据您的回答:状态栏将会重叠但不会覆盖主视图。它将会重叠到您添加的自定义视图上。我的问题是如何避免状态栏的重叠。希望您能理解。 - Ganapathy
使用未声明的标识符'kDeviceiPad'。 - Moob
@Moob - "kDeviceiPad"是nsuserdefault,用于检查您是否正在使用iPad。您可以编写自己的代码来检查iPad。 - Vizllx
1
为什么不将您的固定宽度更改为self.window.frame.size.width呢?这样您就不需要检查设备类型了。 - Tung Do

6
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
    // Override point for customization after application launch.
    self.viewController = [[[ViewController alloc] initWithNibName:@"ViewController" bundle:nil] autorelease];

    self.window.rootViewController = self.viewController;

 if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7) {

        [application setStatusBarStyle:UIStatusBarStyleLightContent];
         [application setStatusBarHidden:NO withAnimation:UIStatusBarAnimationFade];

        self.window.clipsToBounds =YES;            
        self.window.frame =CGRectMake(0,20,self.window.frame.size.width,self.window.frame.size.height-20);
    }


   [self.window makeKeyAndVisible];
    return YES;
}

将以下内容设置为info.plist:

视图控制器基于状态栏外观 = NO;


3
在这里,我们可以一次性为所有视图完成这项工作。
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 
{
// Notification for the orientaiton change
[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(applicationDidChangeStatusBarOrientation:)
                                             name:UIApplicationDidChangeStatusBarOrientationNotification
                                           object:nil];

// Window framing changes condition for iOS7 or greater
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7) {
    statusBarBackgroundView = [[UIView alloc] initWithFrame:CGRectMake(0, -20, self.window.frame.size.width, 20)];//statusBarBackgroundView is normal uiview
    statusBarBackgroundView.backgroundColor = [UIColor colorWithWhite:0.000 alpha:0.730];
    [self.window addSubview:statusBarBackgroundView];
    self.window.bounds = CGRectMake(0, -20, self.window.frame.size.width, self.window.frame.size.height);
}
// Window framing changes condition for iOS7 or greater

self.window.rootViewController = navigationController;
[self.window makeKeyAndVisible];


return YES;
}

当我们使用方向时,可以在应用程序委托中添加以下方法来通过方向进行设置。
- (void)applicationDidChangeStatusBarOrientation:(NSNotification *)notification
{
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7) {
    statusBarBackgroundView.hidden = YES;
    UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
    int width = [[UIScreen mainScreen] bounds].size.width;
    int height = [[UIScreen mainScreen] bounds].size.height;

    switch (orientation) {
        case UIInterfaceOrientationLandscapeLeft:
            self.window.bounds =  CGRectMake(-20,0,width,height);
            statusBarBackgroundView.frame = CGRectMake(-20, 0, 20, height);
            break;
        case UIInterfaceOrientationLandscapeRight:
            self.window.bounds =  CGRectMake(20,0,width,height);
            statusBarBackgroundView.frame = CGRectMake(320, 0, 20, height);
            break;
        case UIInterfaceOrientationPortraitUpsideDown:
            statusBarBackgroundView.frame = CGRectMake(0, 568, width, 20);
            self.window.bounds =  CGRectMake(0, 20, width, height);
            break;
        default:
            statusBarBackgroundView.frame = CGRectMake(0, -20, width, 20);
            self.window.bounds =  CGRectMake(0, -20, width, height);
            break;
    }
    statusBarBackgroundView.hidden = NO;
}
}

你需要为此添加以下导航控制器类别
.h
#import <UIKit/UIKit.h>
#import <QuartzCore/QuartzCore.h>
@interface UINavigationController (iOS6fix)

@end

.m

#import "UINavigationController+iOS6fix.h"
@implementation UINavigationController (iOS6fix)  

-(BOOL)shouldAutorotate
{
      return [[self.viewControllers lastObject] shouldAutorotate];
}

-(NSUInteger)supportedInterfaceOrientations
{
      return [[self.viewControllers lastObject] supportedInterfaceOrientations];
}

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
     return [[self.viewControllers lastObject] preferredInterfaceOrientationForPresentation];
}

@end

3

非常非常简单的答案:

通过将“Top Layout Guide”控制拖动到您的视图并设置“垂直”约束,将您的视图顶部与“顶部布局指南”对齐。 参考此答案

工作原理是 - “顶部布局指南”将根据状态栏的存在与否自动调整,并且所有操作均可正常工作 - 无需编写代码!

P.S. 在这个特定的示例中,通过将视图底部的适当垂直约束设置为其父视图等方式,也应该解决底部显示背景的问题...


3
要隐藏iOS7中的状态栏,请按照以下简单步骤进行:
1. 在Xcode中进入“资源”文件夹并打开“(应用程序名称)-Info.plist文件”。
2. 检查“View controller based status bar appearance”键并将其值设置为“NO”。
3. 检查“Status bar is initially hidden”键并将其值设置为“YES”。
如果这些键不存在,则可以通过在顶部选择“信息属性列表”并点击+图标来添加它们。

1
只需在 viewWillAppear 中设置以下代码即可。保留 HTML 不进行解释。
 if ([[[UIDevice currentDevice] systemVersion] floatValue]<= 7) {
    self.edgesForExtendedLayout = UIRectEdgeNone;
 }

1
我通过使用以下代码解决了这个问题。
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
 {
    if(landScape mode)

       if ([UIDevice currentDevice].systemVersion.floatValue>=7) {
        CGRect frame = self.window.frame;
       frame.size.width -= 20.0f;
      frame.origin.x+= 20.0f;
       self.window.frame = frame;
    }


 if(portrait)

    if ([[[UIDevice currentDevice]systemVersion]floatValue] >= 7.0) {
    [application setStatusBarStyle:UIStatusBarStyleLightContent];

    CGRect frame = self.window.frame;
    frame.origin.y += 20.0f;
    frame.size.height -= 20.0f;
    self.window.frame = frame;
}
return YES;

 }

非常感谢。我已经应用并定制了这段代码。这对我很有帮助。 - user3182143

1
#define _kisiOS7 ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0)

 if (_kisiOS7)
    {
        [[UINavigationBar appearance] setBarTintColor:_kColorFromHEX(@"#011C47")];
    }
    else
    {
        [[UINavigationBar appearance] setBackgroundColor:_kColorFromHEX(@"#011C47")];
        [[UINavigationBar appearance] setTintColor:_kColorFromHEX(@"#011C47")];
    }

1
使用Salesforce SDK 2.1(Cordova 2.3.0),我们需要执行以下操作,才能在应用程序的初始加载和从后台返回时显示状态栏(iPhone和iPad):
与此处发布的其他解决方案相反,这个解决方案似乎可以在设备旋转时生效。
1-创建SFHybridViewController的一个类别
#import "SFHybridViewController+Amalto.h"

@implementation SFHybridViewController (Amalto)

- (void)viewWillAppear:(BOOL)animated
    {
        //Lower screen 20px on ios 7
        if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7) {
            CGRect viewBounds = self.view.bounds;
            viewBounds.origin.y = 20;
            viewBounds.size.height = viewBounds.size.height - 20;
            self.webView.frame = viewBounds;
        }

    [super viewWillAppear:animated];
    }

    - (void)viewDidLoad
    {

        if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7) {
            CGRect viewBounds = self.view.bounds;
            viewBounds.origin.y = 20;
            viewBounds.size.height = viewBounds.size.height - 20;
            self.webView.frame = viewBounds;
        }
        [super viewDidLoad];
    }

@end

2-将以下代码添加到AppDelegate.m中的导入部分

#import "SFHybridViewController+Amalto.h"

3-AppDelegatedidFinishLaunchingWithOptions 方法末尾注入

//Make the status bar appear
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7) {

    [application setStatusBarStyle:UIStatusBarStyleLightContent];
    [application setStatusBarHidden:NO withAnimation:UIStatusBarAnimationFade];
}

4-将属性添加到App-Info.plist

View controller-based status bar appearance的值为NO


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接