The first screen of my application is a UITableViewController without a navigation bar, which means that the content flows under the status bar so there's a lot of text collisions. I've adjusted both the properties for Under top bars and Adjust scroll view insets which do actually stop it from scrolling under, but at the cost of keeping the top of the table view under. I've attempted to set the UITableView frame to offset by 20 pixels, but it doesn't appear to take effect and as I currently need the app to be compatible with iOS 6 I can't jump to iOS 7 Storyboards to force autolayout to use the top height guide. Has anyone found a solution that works for both versions?

我尝试过的事情:设置edgesForExtendedLayout,在Storyboard中更改顶部栏下的设置和调整滚动视图,迫使框架到一个新的区域。

一图胜千言万语:


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

EDIT

你可以在IB中,通过使用iOS6/iOS7增量。在iOS 7中设置你的位置,然后在iOS 6中设置Y为-20点。更多信息请参见这个SO问题。


我认为使用UITableViewController的方法可能和你们之前做的有点不同。这对我来说很有效,但你可能不会喜欢。我所做的是有一个视图控制器和一个指向UItableViewController的容器视图。这样我就可以使用TopLayoutGuide提供给我的故事板。只要把约束添加到容器视图,你就可以兼顾iOS7和iOS6了。


对于任何有兴趣复制此操作的人,只需遵循以下步骤:

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

如果你按照上面的步骤,当你运行应用程序时,你会发现什么都没有,包括调整Xcode的复选框“扩展边下{上,下,不透明}条”,以阻止第一行出现在状态栏下,你也不能通过编程来解决这个问题。

例:在上述情况下,以下内容将不起作用:

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

这个问题非常令人沮丧,我相信这是苹果的一个bug,特别是因为它出现在他们自己的对象库中预先连接的UITableViewController中。

我不同意那些试图用任何形式的“神奇数字”来解决这个问题的人。“使用20px的delta”。这种紧密耦合的编程绝对不是苹果想让我们在这里做的。

对于这个问题,我发现了两个解决方案:

Preserving the UITableViewController's scene: If you would like to keep the UITableViewController in the storyboard, without manually placing it into another view, you can embed the UITableViewController in a UINavigationController (Editor > Embed In > Navigation Controller) and uncheck "Shows Navigation Bar" in the inspector. This solves the issue with no extra tweaking needed, and it also preserves your UITableViewController's scene in the storyboard. Using AutoLayout and embedding the UITableView into another view (I believe this is how Apple wants us to do this): Create an empty UIViewController and drag your UITableView in it. Then, Ctrl-drag from your UITableView towards the status bar. As the mouse gets to the bottom of the status bar, you will see an Autolayout bubble that says "Top Layout Guide". Release the mouse and choose "Vertical Spacing". That will tell the layout system to place it right below the status bar.

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


请注意:这适用于以下配置:

屏幕顶部没有导航栏(表视图满足状态栏) 表视图不可滚动

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

最初的发布

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

- (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部分)。


在你的故事板上选择UIViewController,取消选中顶部栏下的扩展边。 为我工作。 : )


如果你用编程的方式做事情,并且使用一个没有UINavigationController的UITableViewController,你最好的选择是在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仍然会滚动到状态栏后面,但当滚动到顶部时,不会在状态栏下面。


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


我最终使用了一个额外的背景视图,添加在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


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

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

分享和享受…


我这样做的视网膜/非视网膜显示

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

我把它的工作大小设置为自由形式


我不知道这有多合理,但我发现这个方案将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中使用基于视图控制器的状态栏外观= NO和状态栏样式=不透明的黑色样式,来实现全局。

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


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]];

干杯,本


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

添加一个Viewcontroller并将其作为初始视图。这将显示关键的顶部和底部布局指南。

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

做所有的事情来改造表到新的控制器:

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

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

重新连接故事板中需要的任何东西,比如搜索栏。

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

然后我点击所有地方,直到我找到垂直空间约束,并将其顶部值从-20改为0,它完美地工作了。


再加上上面的答案:

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

TLDR;顶部答案的第二个解决方案几乎是可行的,但对于某些版本的xCode, ctrl+拖动到“顶部布局指南”并选择垂直间距不起作用。然而,首先调整表格视图的大小,然后选择“顶部空间到顶部布局指南”即可


将一个空白的ViewController拖到故事板上。 将UITableView对象拖到View中。(不是UITableViewController)。使用蓝色布局指南将其定位在正中心。

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

创建UIViewController的自定义子类,并添加<UITableViewDataSource, UITableViewDelegate>协议。不要忘记在标识检查器中将你的故事板的ViewController设置为这个类。 在你的实现文件中为你的TableView创建一个outlet,命名为TableView

右键单击TableView并将数据源和委托拖到你的ViewController中。

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

抓取你的表视图的顶部边缘,并将其移动到一个虚线蓝色的自动布局指南,是靠近顶部

现在,您可以从表格视图控制拖动到顶部,并选择顶部空间到顶部布局指南

它会给你一个关于TableView的模糊布局的错误,只需添加缺少的约束,你就完成了。

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


这是用Swift写的 调整@lipka的回答:

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

我使用一个UISplitViewController与一个导航控制器和一个tableviewcontroller。在尝试了许多解决方案后,这对我来说很有效:

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的解决方案,但将子视图应用到navigationController。


查看所有解决方案: 我的项目只是使用xib,所以,解决方案与故事板不为我工作。 自我。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;
    }
}

帮助它起作用。


对于Xcode 7,取消导航栏的“半透明”复选标记对我来说很有效。


override func viewDidLoad() {
 // your code

 if let nc = self.navigationController {
   yourView.frame.origin.y = nc.navigationBar.frame.origin.y + nc.navigationBar.frame.height
  }
}

下面的解决方案在代码中工作得很好,不需要使用神奇的常量,并解释了用户改变大小类,例如通过旋转或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);
}

这将修复一个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
    }
}

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

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

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

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


适用于swift 3 - In 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 11中遇到了这个问题,但ios 8 - 10.3.3的布局是正确的。对于我的案例,我设置垂直空间约束为Superview。Top Margin代替Superview。顶部适用于ios 8 - 11。


对于那些像我一样不愿意在UIViewController中嵌入UITableViewController的人来说,试试这个:

一个自定义的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
}

我发现最简单的方法,尤其是当你在标签栏中添加表格视图时,首先添加一个视图,然后在该视图中添加表格视图。这将为您提供您正在寻找的最高边际指导。