219

我的应用程序的第一个屏幕是UITableViewController没有导航栏的,这意味着内容在状态栏下流动,因此有很多文本冲突。我已经调整了两个属性,Under top bars并且Adjust scroll view insets确实阻止了它向下滚动,但代价是保持表格视图的顶部在下面。我试图将UITableView框架设置为偏移 20 像素,但它似乎没有生效,因为我目前需要该应用程序与 iOS 6 兼容,所以我无法跳转到 iOS 7 Storyboards 来强制使用自动布局顶部高度指南。有没有人找到适用于两个版本的解决方案?

我尝试过的事情:设置edgesForExtendedLayout,更改情节提要中的设置Under top barsAdjust scroll view,强制框架到一个新区域。

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

4

27 回答 27

366

对于有兴趣复制此内容的任何人,只需按照以下步骤操作:

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

如果您按照上述步骤操作,当您运行应用程序时,您将看到任何内容,包括将 Xcode 的复选框调整为“在 {Top,Bottom,Opaque} Bars 下扩展边缘”可以阻止第一行出现在状态栏下,你也不能以编程方式解决这个问题。

例如,在上述场景中,以下内容将不起作用

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

UITableViewController这个问题可能非常令人沮丧,我相信这是 Apple 的一个错误,特别是因为它出现在他们自己从对象库中预先连接的部分中。

我不同意所有试图通过使用任何形式的“幻数”来解决这个问题的人,例如“使用 20 像素的增量”。这种紧耦合的编程绝对不是苹果希望我们在这里做的。

我发现了解决此问题的两种方法:

  • 保留UITableViewController场景
    如果您想保留UITableViewController情节提要中的 ,而不手动将其放置到另一个视图中,您可以将其嵌入UITableViewControllerUINavigationController编辑器>嵌入>导航控制器)并取消选中检查器中的“显示导航栏” . 这解决了不需要额外调整的问题,并且还保留UITableViewController了情节提要中的场景。

  • 使用 AutoLayout 并将其嵌入UITableView到另一个视图中 (我相信这就是 Apple 希望我们这样做的方式)
    创建一个空UIViewController并将您的拖入UITableView其中。UITableView然后,按住 Ctrl 键从您的状态栏拖动。当鼠标移到状态栏的底部时,您会看到一个自动布局气泡,上面写着“顶部布局指南”。释放鼠标并选择“垂直间距”。这将告诉布局系统将其放置在状态栏的正下方。

我已经在一个空的应用程序上测试了两种方式,它们都可以工作。您可能需要做一些额外的调整以使它们适用于您的项目。

于 2013-09-23T04:28:03.423 回答
86

如果您以编程方式做事并且没有使用 a UITableViewController,那么UINavigationController最好的选择是在 中执行以下操作viewDidLoad

斯威夫特 3

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

早期的斯威夫特

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

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

于 2013-10-17T10:46:03.340 回答
24

请注意:这对我来说适用于以下配置:

  • 屏幕顶部没有导航栏(表格视图遇到状态栏)
  • 表格视图不可滚动

如果不满足上述两个要求,您的里程可能会有所不同。

原帖

我以编程方式创建了我的视图,这最终对我有用:

- (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;
    }
}

来源(在pg.39底部的 topLayoutGuide 部分)。

于 2013-09-24T08:21:21.710 回答
20

添加到最佳答案:

在第二种方法最初似乎不起作用之后,我做了一些额外的修补并找到了解决方案。

TLDR;最佳答案的第二个解决方案几乎可以工作,但对于某些版本的 xCode ctrl+拖动到“顶部布局指南”并选择垂直间距什么都不做。但是,通过首先调整 Table View 的大小,然后选择“Top Space to Top Layout Guide”可以工作


  1. 将一个空白的 ViewController 拖到情节提要上。 视图控制器

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

表视图 中心图像

  1. 将 UITableViewCell 拖到 TableView 中。这将是您的原型重用单元格,因此不要忘记在“属性”选项卡下将其设置为重用标识符,否则您会崩溃。

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

  1. 创建 UIViewController 的自定义子类,并添加<UITableViewDataSource, UITableViewDelegate>协议。不要忘记在 Identity Inspector 中将 Storyboard 的 ViewController 设置为此类。

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

创建出口 表视图

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

数据源委托

现在对于不剪辑到状态栏的部分。

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

调整大小

  1. 现在,您可以控制从 Table View 拖动到顶部并选择 Top Space to Top Layout Guide

顶部空间到顶部布局指南

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

添加缺少的约束

现在你可以像平常一样设置你的表格视图,而且它不会剪辑状态栏!

于 2014-12-27T23:27:04.057 回答
11
- (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

于 2013-10-26T20:08:12.737 回答
8

这是如何在“Swift”中编写它对@lipka 答案的调整:

tableView.contentInset = UIEdgeInsetsMake(20.0, 0.0, 0.0, 0.0)
于 2015-01-12T21:12:33.627 回答
8

在情节提要上选择 UIViewController 并取消选中 Extend Edges Under Top Bars 选项。为我工作。:)

于 2013-10-03T15:19:59.477 回答
5

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

在此处输入图像描述

于 2016-02-20T11:33:06.980 回答
3

这将为 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
    }
}
于 2016-07-29T23:42:05.453 回答
2

我不知道它是如何 Kosher 的,但我发现这个方案将 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];
    }

当然,用redColor你想要的背景颜色替换。

您必须单独进行其中一项调配以设置状态栏中字符/符号的颜色。我在 plist 中使用View controller-based status bar appearance = NOand来全局执行此操作。Status bar style = Opaque black style

似乎有效,我很想知道它的任何错误或问题。

于 2014-01-22T22:08:47.320 回答
2

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

在以编程方式创建 TableViewControllers 时,我发现最简洁的解决方案是将 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]];

干杯,本

于 2014-05-16T22:52:25.753 回答
2

适用于 swift 3 - 在 vi​​ewDidLoad();

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. 为滚动指示器提供相同的插图,因此它出现在状态栏下方。

于 2017-02-11T11:07:10.153 回答
1

我最终使用了一个具有所需背景的额外视图,在 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];

它不是很漂亮,但它是相当简单的解决方案,如果您需要使用 xib-less 视图以及 IOS6 和 IOS7

于 2013-11-16T10:53:42.060 回答
1

我认为使用 UITableViewController 的方法可能与您之前所做的有点不同。它对我有用,但你可能不喜欢它。我所做的是有一个带有指向我的 UItableViewController 的容器视图的视图控制器。这样我就可以使用提供给我的故事板的 TopLayoutGuide。只需将约束添加到容器视图中,iOS7 和 iOS6 都应注意。

于 2013-09-22T22:03:19.447 回答
1

我已经为 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;
}
于 2013-11-26T11:51:59.987 回答
1

对于像我这样不想嵌入它们UITableViewController的人来说,UIViewController试试这个:

自定义UITableViewController子类可以将掩码视图附加到 tableView 的父视图。在 viewDidAppear 上添加遮罩,在 viewWillDisappear 上移除遮罩。

private var statusBarMaskView: UIView!

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)

    if let superview = self.tableView.superview {
        self.statusBarMaskView = UIView(frame: CGRect.zero)
        superview.insertSubview(self.statusBarMaskView, aboveSubview: self.tableView)
        self.statusBarMaskView.backgroundColor = self.tableView.backgroundColor

        // using a nice constraint layout library to set the frame
        self.statusBarMaskView.pinTop(to: superview)
        self.statusBarMaskView.pinLeft(to: superview)
        self.statusBarMaskView.pinRight(to: superview)
        self.statusBarMaskView.addHeightConstraint(with: 22.0)
        ////
    }
}

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)

    self.statusBarMaskView.removeFromSuperview()
    self.statusBarMaskView = nil
}
于 2018-10-15T01:07:33.163 回答
1

以下解决方案在不使用魔术常量的情况下在代码中运行良好,并考虑到用户更改大小类,例如通过 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);
}
于 2016-07-21T02:21:20.830 回答
0

I had a UISearchBar at the top of my UITableView and the following worked;

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

Share and enjoy...

于 2013-11-22T21:43:06.460 回答
0

Abrahamchez 的解决方案 https://developer.apple.com/library/ios/qa/qa1797/_index.html 为我工作如下。我有一个 UITableviewcontroller 作为我的初始视图。我曾尝试过偏移代码并嵌入到 navcon 中,但都没有解决状态栏透明度问题。

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

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

做所有的事情来将表改装到新的控制器中:

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

将 UITableViewDataSource 和 UITableViewDelegate 添加到 viewcontroller 的 .h 中。

重新连接情节提要中所需的任何内容,例如搜索栏。

最重要的是设置约束,就像在 Apple Q&A 中一样。我没有费心插入工具栏。不确定确切的顺序。但是可能在我构建时,布局指南上出现了一个红色图标。我单击它并让 Xcode 安装/清理约束。

然后我到处点击,直到找到 Vertical Space 约束并将其顶部值从 -20 更改为 0,并且效果很好。

于 2014-07-04T17:58:35.530 回答
0

我通过将大小设置为自由格式来实现它

在此处输入图像描述

于 2013-12-22T16:09:16.537 回答
0

我正在使用带有导航控制器和 tableviewcontroller 的 UISplitViewController。在此处尝试了许多解决方案后,这在主视图中对我有用:

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 的解决方案,但将子视图应用于导航控制器。

于 2015-01-23T06:03:37.473 回答
0
override func viewDidLoad() {
 // your code

 if let nc = self.navigationController {
   yourView.frame.origin.y = nc.navigationBar.frame.origin.y + nc.navigationBar.frame.height
  }
}
于 2016-02-24T10:41:12.230 回答
0

我找到了执行此操作的最简单方法,特别是如果您在选项卡栏内添加表格视图是首先添加一个视图然后在该视图中添加表格视图。这为您提供了您正在寻找的顶部边距指南。

在此处输入图像描述

于 2020-02-14T20:45:57.600 回答
0

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

在此处输入图像描述

于 2017-09-26T19:27:44.113 回答
0

这是一个 Swift 2.3。(Xcode 8.0) 解决方案。我创建了 UITableView 的子类。

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

内容插图应始终为零(默认情况下)。我手动将其设置为零。您还可以添加一个检查方法来进行检查,如果它不是您想要的,只需获取正确的矩形即可。更改只会在绘制 tableview 时反映出来(这不会经常发生)。

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

于 2016-10-06T10:09:43.257 回答
-1

查看所有解决方案:我的项目只是使用 xib,因此,带有情节提要的解决方案对我不起作用。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;
    }
}

帮助这个工作。

于 2015-07-04T03:16:00.577 回答
-2

如果您还需要支持 iOS 6,则必须有条件地将其向下移动。也就是说,在 iOS 7 中,您只需将其向下移动 20 点(通过frame操作或使用自动布局),而在 iOS 6 中,您无需处理它。我不相信你可以在 IB 中做到这一点,所以你必须在代码中做到这一点。

编辑

您实际上可以在 IB 中通过使用 iOS6/iOS7 deltas 来执行此操作。在 iOS 7 中设置您的位置,然后在 iOS 6 中将 delta Y 设置为 -20 点。有关更多信息,请参阅此 SO 问题

于 2013-09-19T19:01:50.740 回答