iOS 7:UITableView显示在状态栏下

iOS 7:UITableView显示在状态栏下,ios,ios7,uistatusbar,Ios,Ios7,Uistatusbar,我的应用程序的第一个屏幕是一个没有导航栏的UITableViewController,这意味着内容在状态栏下流动,因此存在大量文本冲突。我已经调整了顶部栏下的属性和调整滚动视图插入项,这实际上阻止了它在下面滚动,但代价是将表视图的顶部保持在下面。我已尝试将UITableView帧设置为偏移20像素,但它似乎没有生效,而且由于我当前需要应用程序与iOS 6兼容,我无法跳转到iOS 7故事板以强制自动布局使用顶部高度指南。是否有人找到了一个同时适用于两个版本的解决方案 我尝试过的方法:设置edges

我的应用程序的第一个屏幕是一个没有导航栏的
UITableViewController
,这意味着内容在状态栏下流动,因此存在大量文本冲突。我已经调整了顶部栏下的
属性和
调整滚动视图插入项
,这实际上阻止了它在下面滚动,但代价是将表视图的顶部保持在下面。我已尝试将
UITableView
帧设置为偏移20像素,但它似乎没有生效,而且由于我当前需要应用程序与iOS 6兼容,我无法跳转到iOS 7故事板以强制自动布局使用顶部高度指南。是否有人找到了一个同时适用于两个版本的解决方案

我尝试过的方法:设置
edgesForExtendedLayout
,在故事板中更改顶部栏下
的设置,以及
调整滚动视图
,强制帧到新区域

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

编辑


实际上,您可以在IB中通过使用iOS6/iOS7增量来实现这一点。在iOS 7中设置您的位置,然后在iOS 6中将增量Y设置为-20点。有关更多信息,请参阅。

我认为使用UITableViewController的方法可能与您以前所做的略有不同。这对我很有用,但你可能不是它的粉丝。我所做的是有一个视图控制器,它带有指向我的UItableViewController的容器视图。通过这种方式,我可以在故事板中使用提供给我的TopLayoutGuide。只需将约束添加到容器视图中,您就可以同时使用iOS7和iOS6了。

对于任何有兴趣复制此约束的人,只需执行以下步骤:

  • 创建一个新的iOS项目
  • 打开主情节提要并删除默认/初始
    UIViewController
  • 从对象库中拖出一个新的
    UITableViewController
  • 将其设置为初始视图控制器
  • 向表格提供一些测试数据
  • 如果您按照上述步骤操作,当您运行应用程序时,您将看到没有任何东西可以阻止第一行出现在状态栏下,包括调整Xcode的复选框以“在{Top,Bottom,不透明}条下延伸边”,您也无法通过编程解决此问题

    例如,在上述情况下,以下情况不会产生任何影响:

    // These do not work
    self.edgesForExtendedLayout=UIRectEdgeNone;
    self.extendedLayoutIncludesOpaqueBars=NO;
    self.automaticallyAdjustsScrollViewInsets=NO;
    
    这个问题可能非常令人沮丧,我认为这是苹果方面的一个缺陷,特别是因为它出现在他们自己的对象库中的预连线
    UITableViewController

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

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

    • 保存
      UITableViewController
      的场景

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

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


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

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

    • 屏幕顶部没有导航栏(表视图符合状态栏)
    • 表视图是不可滚动的
    如果上述两个要求不满足,您的差异可能会有所不同

    原创帖子

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

    - (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,取消选中顶部栏下的“延伸边缘”选项。 为我工作。
    :)

    如果您以编程方式进行操作,并且使用的是
    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
    仍将滚动到状态栏后面,但滚动到顶部时不会在状态栏下面

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

    我最后使用了一个具有所需背景的额外视图,添加在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的视图,并且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;
    }
    

    我通过将大小设置为“自由形式”使其工作


    我不知道它有多洁净,但我不知道
    - (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];
        }
    
    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]];
    
    tableView.contentInset = UIEdgeInsetsMake(20.0, 0.0, 0.0, 0.0)
    
    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];
    }
    
    - (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;
        }
    }
    
    override func viewDidLoad() {
     // your code
    
     if let nc = self.navigationController {
       yourView.frame.origin.y = nc.navigationBar.frame.origin.y + nc.navigationBar.frame.height
      }
    }
    
    - (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);
    }
    
    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
        }
    }
    
    class MYCustomTableView: UITableView
    {   
        override func drawRect(rect: CGRect) {
            super.drawRect(rect)
            contentInset    = UIEdgeInsetsZero
        }
    }
    
    let statusBarHeight = UIApplication.shared.statusBarFrame.height
    
    let insets = UIEdgeInsets(top: statusBarHeight, left: 0, bottom: 0, right: 0)
    tableView.contentInset = insets
    tableView.scrollIndicatorInsets = insets
    
    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
    }