iOS 7:UITableView显示在状态栏下

我的应用程序的第一个屏幕是没有导航栏的UITableViewController ,这意味着内容在状态栏下面stream动,所以有很多文本冲突。 我已经调整了两个属性Under top barsAdjust scroll view insets实际上停止滚动下,但代价保持顶部的表视图下。 我试图设置UITableView框架偏移20像素,但它似乎没有生效,因为我目前需要应用程序与iOS 6兼容我不能跳转到iOS 7故事板强制自动布局使用顶部高度指南。 有没有人find了适用于两个版本的解决scheme?

我尝试过的东西:设置edgesForExtendedLayout ,改变故事板内的设置Under top barsAdjust scroll view ,迫使框架到一个新的领域。

一张图片胜过千言万语: 状态栏下的流程

对于任何有兴趣复制这个,只需按照下列步骤:

  1. 创build一个新的iOS项目
  2. 打开主要故事板并删除默认/初始UIViewController
  3. 从对象库中拖出一个新的UITableViewController
  4. 将其设置为初始视图控制器
  5. 给表格提供一些testing数据

如果你按照上面的步骤,当你运行应用程序,你会看到没有任何东西,包括调整Xcode的checkbox,以“在{顶部,底部,不透明}酒吧下延长边缘”的作品,以阻止第一行出现在状态栏下,你也不能通过编程来解决这个问题。

例如在上面的情况下,以下将不起作用:

 // These do not work self.edgesForExtendedLayout=UIRectEdgeNone; self.extendedLayoutIncludesOpaqueBars=NO; self.automaticallyAdjustsScrollViewInsets=NO; 

这个问题可能非常令人沮丧,我相信这是苹果公司的一个漏洞,尤其是因为它在对象库中预先连线的UITableViewController

我不同意使用任何forms的“幻数”来解决这个问题,比如“使用20px”。 这种紧密耦合的编程绝对不是苹果希望我们在这里做的。

我发现了这个问题的两个解决scheme:

  • 保留UITableViewController的场景
    如果您想将UITableViewController保留在故事板中,而不手动放置到另一个视图中,则可以将UITableViewControllerembedded到UINavigationController (Editor> Embed In> Navigation Controller)中,并在检查器中取消选中“显示导航栏”。 这就解决了这个问题,不需要额外的调整,它也保留了你的UITableViewController在故事板中的场景。

  • 使用AutoLayout并将UITableViewembedded到另一个视图 (我相信这是苹果公司希望我们这样做)
    创build一个空的UIViewController并拖动你的UITableView 。 然后,按住Ctrl从你的UITableView拖到状态栏。 当鼠标到达状态栏的底部时,你会看到一个Autolay的泡泡,上面写着“Top Layout Guide”。 释放鼠标并select“垂直间距”。 这将告诉布局系统将其置于状态栏的正下方。

我已经在一个空的应用程序上testing了这两种方法,他们都工作。 您可能需要做一些额外的调整才能使其为您的项目工作。

如果你正在做的事情编程,并使用UITableViewController没有UINavigationController最好的select是在viewDidLoad执行以下操作:

Swift 3

 self.tableView.contentInset = UIEdgeInsets(top: 20, left: 0, bottom: 0, right: 0) 

早些时候Swift

 self.tableView.contentInset = UIEdgeInsetsMake(20.0f, 0.0f, 0.0f, 0.0f); 

UITableViewController仍然会滚动到状态栏的后面,但在滚动到顶部时不会在它之下。

请注意:这对我工作以下configuration:

  • 屏幕顶部没有导航栏(表格视图符合状态栏)
  • 表视图是不可滚动的

如果上述两项要求不符合,您的milage可能会有所不同。

原始post

我以编程的方式创build了我的视图,并最终为我工作:

 - (void) viewDidLayoutSubviews { // only works for iOS 7+ if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0) { CGRect viewBounds = self.view.bounds; CGFloat topBarOffset = self.topLayoutGuide.length; // snaps the view under the status bar (iOS 6 style) viewBounds.origin.y = topBarOffset * -1; // shrink the bounds of your view to compensate for the offset viewBounds.size.height = viewBounds.size.height + (topBarOffset * -1); self.view.bounds = viewBounds; } } 

来源 (在第39页底部的topLayoutGuide部分)。

添加到最上面的答案:

第二种方法后,似乎没有起作用,我做了一些额外的修补,并find了解决办法。

TLDR; 最佳答案的第二个解决scheme几乎可以工作,但对于某些版本的xCode ctrl +拖动到“顶部布局指南”,并select垂直间距什么也不做。 但是,首先调整表视图的大小,然后select“顶部空间到顶部布局指南”的作品


  1. 将一个空白的ViewController拖到故事板上。 视图控制器

  2. 将UITableView 对象拖到视图中。 (不是UITableViewController)。 使用蓝色布局指南将其放置在正中央。

表视图中心图像

  1. 将一个UITableViewCell拖到TableView中。 这将是您的原型重用单元格,所以不要忘记在属性选项卡下设置它的重用标识符,否则您将会崩溃。

添加表格视图单元格重用标识符

  1. 创build您的UIViewController的自定义子类,并添加<UITableViewDataSource, UITableViewDelegate>协议。 不要忘记在Identity Inspector中将故事板的ViewController设置为这个类。

  2. 在您的实现文件中为您的TableView创build一个出口,并将其命名为“tableView”

创建出口的tableView

  1. 右键单击TableView并将数据源和委托拖动到您的ViewController。

dataSource委托

现在为不剪切到状态栏的部分。

  1. 抓住桌面视图的顶部边缘,将其向下移动到靠近顶部的虚线蓝色自动布局指南之一

调整

  1. 现在,您可以控制从“表格视图”拖动到顶部,并select“顶部空间到顶部布局指南”

顶部空间到顶部布局指南

  1. 它会给你一个关于TableView模糊布局的错误,只是添加缺less约束和你完成。

添加缺少约束

现在,您可以像正常一样设置您的表格视图,并且不会剪辑状态栏!

 - (void) viewDidLayoutSubviews { if (floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_6_1) { self.navigationController.navigationBar.barStyle = UIBarStyleBlackOpaque; if ([self respondsToSelector:@selector(edgesForExtendedLayout)]) self.edgesForExtendedLayout = UIRectEdgeNone; // iOS 7 specific CGRect viewBounds = self.view.bounds; CGFloat topBarOffset = self.topLayoutGuide.length; viewBounds.origin.y = topBarOffset * -1; self.view.bounds = viewBounds; self.navigationController.navigationBar.translucent = NO; } } 

https://developer.apple.com/library/ios/documentation/userexperience/conceptual/TransitionGuide/SupportingEarlieriOS.html#//apple_ref/doc/uid/TP40013174-CH14-SW1

这是如何写在“斯威夫特”调整@ lipka的答案:

 tableView.contentInset = UIEdgeInsetsMake(20.0, 0.0, 0.0, 0.0) 

select您的故事板上的UIViewController取消选项Extend Edges Under Top Bars。 为我工作。 :)

对于Xcode 7,取消勾选导航栏的“半透明”复选标记对我有用。

在这里输入图像说明

这将解决它的UITableViewController(没有任何幻数)。 我无法解决的唯一的问题是,如果你正在打电话,在这种情况下,tableView的顶部被推下太多。 如果有人知道如何解决这个问题,请告诉我们。

 class MyTableViewController: UITableViewController { override func viewDidLoad() { super.viewDidLoad() configureTableViewTop() } override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) { super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator) coordinator.animateAlongsideTransition({ (context) -> Void in }, completion: { (context) -> Void in self.configureTableViewTop() }) } func configureTableViewTop() { tableView.contentInset.top = UIApplication.sharedApplication().statusBarFrame.height } } 

我不知道它是如何犹太教,但我发现这个计划移动ViewController的视图,并提供了一个坚实的背景状态栏:

 - (void)viewDidLoad { [super viewDidLoad]; // Shove everything down if iOS 7 or later float systemVersion = [[[UIDevice currentDevice] systemVersion] floatValue]; if (systemVersion >= 7.0f) { // Move the view down 20 pixels CGRect bounds = self.view.bounds; bounds.origin.y -= 20.0; [self.view setBounds:bounds]; // Create a solid color background for the status bar CGRect statusFrame = CGRectMake(0.0, -20.0, bounds.size.width, 20); UIView* statusBar = [[UIView alloc] initWithFrame:statusFrame]; statusBar.backgroundColor = [UIColor redColor]; [self.view addSubview:statusBar]; } 

当然,用任何你想要的背景颜色replaceredColor

您必须单独做一个swizzles来设置状态栏中的字符/符号的颜色。 我使用View controller-based status bar appearance = NOStatus bar style = Opaque black style在plist中Status bar style = Opaque black style ,全局做到这一点。

似乎工作,我有兴趣听到任何错误或问题。

chappjc的答案在使用XIB时效果很好。

通过编程创buildTableViewController时,我发现最简洁的解决scheme是将UITableViewController实例包装到另一个UIViewController中并相应地设置约束。

这里是:

 UIViewController *containerLeftViewController = [[UIViewController alloc] init]; UITableViewController *tableViewController = [[UITableViewController alloc] init]; containerLeftViewController.view.backgroundColor = [UIColor redColor]; hostsAndMoreTableViewController.view.translatesAutoresizingMaskIntoConstraints = NO; [containerLeftViewController.view addSubview:tableViewController.view]; [containerLeftViewController addChildViewController:tableViewController]; [tableViewController didMoveToParentViewController:containerLeftViewController]; NSDictionary * viewsDict = @{ @"tableView": tableViewController.view , @"topGuide": containerLeftViewController.topLayoutGuide, @"bottomGuide": containerLeftViewController.bottomLayoutGuide, }; [containerLeftViewController.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[tableView]|" options:0 metrics:nil views:viewsDict]]; [containerLeftViewController.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[topGuide][tableView][bottomGuide]" options:0 metrics:nil views:viewsDict]]; 

干杯,本

我认为使用UITableViewController的方法可能与以前做的有些不同。 它为我工作,但你可能不是它的粉丝。 我所做的是有一个视图控制器的容器视图,指向我的UItableViewController。 这样我就可以使用提供给故事板中的TopLayoutGuide。 只需将约束添加到容器视图,您应该照顾iOS7和iOS6。

我最终使用了一个额外的视图与所需的背景,添加到TableView后,并放置在状态栏:

  self.CoverView = [[UIView alloc]init]; if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0) { self.CoverView.frame = CGRectMake(0,0,self.view.bounds.size.width,20); } self.CoverView.backgroundColor = [UIColor whiteColor]; self.TableView = [[UITableView alloc]initWithFrame:CGRectMake(0, self.CoverView.bounds.size.height,XXX, YYY)]; [self.view addSubview:self.TableView]; [self.view addSubview:self.CoverView]; 

这不是很漂亮,但它是一个相当简单的解决scheme,如果你需要使用无xib视图,IOS6和IOS7

以下解决scheme在代码中运行良好,无需使用魔术常量,并且可以说明用户更改大小类,例如通过ipad上的旋转或并排应用程序:

 - (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection { [super traitCollectionDidChange:previousTraitCollection]; // Fix up content offset to ensure the tableview isn't underlapping the status bar. self.tableView.contentInset = UIEdgeInsetsMake(self.topLayoutGuide.length, 0.0, 0.0, 0.0); } 

我有一个UISearchBar在我的UITableView的顶部和下面的工作;

 self.tableView.contentInset = UIEdgeInsetsMake(20, 0, 0, 0); self.tableView.contentOffset = CGPointMake(0, -20); 

分享和享受…

我为Retina / Non-Retina显示器做了这个

 BOOL isRetina = FALSE; if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)]) { if ([[UIScreen mainScreen] scale] == 2.0) { isRetina = TRUE; } else { isRetina = FALSE; } } if (isRetina) { self.edgesForExtendedLayout=UIRectEdgeNone; self.extendedLayoutIncludesOpaqueBars=NO; self.automaticallyAdjustsScrollViewInsets=NO; } 

我通过将大小设置为自由forms来实现它的工作

在这里输入图像说明

Abrahamchez的解决schemehttps://developer.apple.com/library/ios/qa/qa1797/_index.html为我工作如下。 我有一个单一的UITableview控制器作为我的初始视图。 我已经尝试偏移代码和embedded在navcon中,但都没有解决状态栏的透明度。

添加一个ViewController并使其成为初始视图。 这应该会显示关键的顶部和底部布局指南。

将旧的Tableview拖到新控制器的View中。

做所有的东西来改造表到新的控制器:

将旧的视图controller.h文件更改为从UIViewController,而不是UITableViewController的inheritance/子类。

将UITableViewDataSource和UITableViewDelegate添加到视图控制器的.h。

重新连接故事板中所需的任何内容,例如search栏。

最重要的是要设置好约束条件,就像苹果Q&A一样。 我没有打扰插入一个工具栏。 不确定确切的顺序。 但是布局指南中出现了一个红色的图标,可能是我build造的时候。 我点击它,让Xcode安装/清除约束。

然后,我点击每个地方,直到我发现垂直空间约束,并将其顶值从-20更改为0,它的工作完美。

我正在使用导航控制器和tableviewcontroller的UISplitViewController。 在这里尝试了很多解决scheme后,这在主视图中适用于我:

 float systemVersion = [[[UIDevice currentDevice] systemVersion] floatValue]; if (systemVersion >= 7.0f) { // Move the view down 20 pixels CGRect bounds = self.view.bounds; bounds.origin.y -= 20.0; [self.navigationController.view setBounds:bounds]; // Create a solid color background for the status bar CGRect statusFrame = CGRectMake(0.0, -20.0, bounds.size.width, 20); UIView* statusBar = [[UIView alloc] initWithFrame:statusFrame]; statusBar.backgroundColor = [UIColor whiteColor]; [statusBar setAlpha:1.0f]; [statusBar setOpaque:YES]; [self.navigationController.view addSubview:statusBar]; } 

这与Hot Licks的解决scheme类似,但将子视图应用于navigationController。

 override func viewDidLoad() { // your code if let nc = self.navigationController { yourView.frame.origin.y = nc.navigationBar.frame.origin.y + nc.navigationBar.frame.height } } 

这是一个Swift 2.3。 (Xcode 8.0)解决scheme。 我已经创build了UITableView的子类。

 class MYCustomTableView: UITableView { override func drawRect(rect: CGRect) { super.drawRect(rect) contentInset = UIEdgeInsetsZero } } 

内容插入应始终为零(默认情况下)。 我手动设置零。 你也可以添加一个检查方法,使检查,如果它不是你想要的只是得到正确的矩形。 只有在绘制tableview时才会反映这种变化(这种情况经常不会发生)。

不要忘记更新你的IB中的TableView(在TableViewController中,或者只是在ViewController中的TableView中)。

我在ios 11中遇到了这个问题,但是ios 8 – 10.3.3的布局是正确的。 对于我的情况,我设置了一个垂直空间约束Superview.Top的边缘,而不是Superview.Top适用于ios 8 – 11。

在这里输入图像说明

看到所有的解决scheme:我的项目只是使用xib,所以,故事板的解决scheme不适合我。 self.edgesForExtendedLayout = UIRectEdgeNone; 只要导航栏可见,就可以用于控制器。 但是如果你的视图只是有状态栏,那是行不通的。 所以我结合了两个条件。

 - (void) viewDidLayoutSubviews { float systemVersion = [[[UIDevice currentDevice] systemVersion] floatValue]; if (systemVersion >= 7.0f) { CGRect bounds = self.view.bounds; if(self.navigationController == nil || self.navigationController.isNavigationBarHidden == YES){ bounds.origin.y -= 20.0; [self.view setBounds:bounds]; } else{ self.edgesForExtendedLayout = UIRectEdgeNone; } } 

帮助这个工程。

适用于swift 3 – 在viewDidLoad();

 let statusBarHeight = UIApplication.shared.statusBarFrame.height let insets = UIEdgeInsets(top: statusBarHeight, left: 0, bottom: 0, right: 0) tableView.contentInset = insets tableView.scrollIndicatorInsets = insets 

此代码:1.获取状态栏的高度2.给表格视图的顶部插入一个等于状态栏高度的内容。 3.滚动指示器的插图相同,所以它出现在状态栏下方。

如果您还需要支持iOS 6,则必须有条件地将其降低。 也就是说,在iOS 7中,您应该将其降低20点(通过frame操作或使用自动布局),并且在iOS 6中将其保留。 我不相信你可以在IB这样做,所以你必须在代码中做到这一点。

编辑

实际上,你可以通过使用iOS6 / iOS7三angular洲在IB中做到这一点。 在iOS 7中设置你的位置,然后在iOS 6中将ΔY设置为-20点。 看到这个SO问题的更多信息。

只需为你的tableview设置框架。 并从顶部放下44p。 在iOS 7中一切从左上angular开始。 状态栏也是窗口的一部分。