iOS 7:UITableView显示在状态栏下

时间:2013-09-19 16:40:36

标签: ios ios7 uistatusbar

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

我尝试过的事情:设置edgesForExtendedLayout,更改故事板中Under top barsAdjust scroll view的设置,将框架强制转换为新区域。

一张图片胜过千言万语: Status bar flow under

27 个答案:

答案 0 :(得分:364)

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

  1. 创建新的iOS项目
  2. 打开主故事板并删除默认/初始UIViewController
  3. 从对象库中拖出新的UITableViewController
  4. 将其设置为初始视图控制器
  5. 为表格提供一些测试数据
  6. 如果您按照上述步骤操作,当您运行该应用程序时,您将看到没有任何内容,包括调整Xcode的复选框“在{顶部,底部,不透明}条形图下延伸边缘”可以阻止第一行出现在状态栏,也不能以编程方式解决此问题。

    E.g。在上面的场景中,以下内容将具有效果:

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

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

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

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

    • 保留UITableViewController的场景
      如果您希望将UITableViewController保留在故事板中,而无需手动将其放入另一个视图中,则可以将UITableViewController嵌入UINavigationController(编辑器>嵌入>导航控制器) )并在检查器中取消选中“显示导航栏”。这解决了这个问题,无需额外调整,并且还在故事板中保留了UITableViewController的场景。

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

    我已经在空应用程序上测试了两种方式,但它们都有效。您可能需要做一些额外的调整才能使它们适合您的项目。

答案 1 :(得分:84)

如果您以编程方式执行操作并使用UITableViewController而没有UINavigationController,则最好的选择是在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仍然会滚动到状态栏后面,但滚动到顶部时不会在它下面。

答案 2 :(得分:23)

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

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

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

原帖

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

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

Source(位于第39页底部的 topLayoutGuide 部分)。

答案 3 :(得分:20)

添加到最佳答案:

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

<强> TLDR;最佳答案的第二个解决方案几乎可以工作,但对于某些版本的xCode ctrl +拖动到&#34;顶部布局指南&#34;并选择Vertical Spacing不做任何事情。但是,首先调整表格视图的大小,然后选择&#34;顶部空间到顶部布局指南&#34;作品


  1. 将空白ViewController拖到故事板上。 View Controller

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

  3. Table View Center Image

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

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

      2. 在您的实施文件中为您的TableView创建一个插座,并将其命名为&#34; tableView&#34;

      3. Create Outlet tableView

        1. 右键单击TableView并将dataSource和委托拖到ViewController。
        2. dataSource delegate

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

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

            1. 现在,您可以控制从“表格视图”拖动到顶部并选择“顶部空间到顶部布局指南”
            2. Top Space to Top Layout Guide

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

                现在您可以像平常一样设置表格视图,但它不会剪切状态栏!

答案 4 :(得分: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

答案 5 :(得分:8)

这是如何在&#34; Swift&#34; 调整@ lipka的答案:

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

答案 6 :(得分:6)

在故事板上选择UIViewController,取消选中“在顶栏下扩展边缘”选项。 为我工作。 :)

答案 7 :(得分:5)

对于Xcode 7,取消勾选半透明&#39;导航栏的复选标记为我工作。

enter image description here

答案 8 :(得分: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
    }
}

答案 9 :(得分: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 = NOStatus bar style = Opaque black style来全局执行此操作。

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

答案 10 :(得分: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]];

干杯,本

答案 11 :(得分:1)

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

答案 12 :(得分:1)

以下解决方案在代码中运行良好而不使用魔术常量,并且考虑用户更改大小等级,例如通过ipads上的轮换或并排应用程序:

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

答案 13 :(得分:1)

适用于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.使滚动指示器具有相同的插图,因此它显示在状态栏下方。

答案 14 :(得分:1)

我为Retina /非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;
}

答案 15 :(得分: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
}

答案 16 :(得分: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

答案 17 :(得分:0)

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

enter image description here

答案 18 :(得分: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)。

答案 19 :(得分:0)

我发现最简单的方法是这样做,特别是如果要在选项卡栏内添加表格视图,首先是添加视图,然后然后在该视图内添加表格视图。这为您提供了所需的顶级利润指南。

enter image description here

答案 20 :(得分:0)

override func viewDidLoad() {
 // your code

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

答案 21 :(得分:0)

我正在使用带有navigationcontroller和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&#39;解决方案,但将子视图应用于navigationController。

答案 22 :(得分:0)

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

添加Viewcontroller并使其成为初始视图。这应该显示你的关键Top&amp;底部布局指南。

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

将所有内容改装为新控制器:

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

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

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

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

然后我点击了所有地方,直到我找到了“垂直空间”约束并将其最高值从-20更改为0并且效果非常好。

答案 23 :(得分:0)

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

enter image description here

答案 24 :(得分:0)

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

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

分享并享受......

答案 25 :(得分:-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;
    }
}

帮助这项工作。

答案 26 :(得分:-2)

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

修改

您可以在IB中使用iOS6 / iOS7增量实际执行此操作。在iOS 7中设置您的位置,然后在iOS 6中将delta Y设置为-20磅。有关详细信息,请参阅this SO question