ChatGPT解决这个技术问题 Extra ChatGPT

iOS 7:UITableView 显示在状态栏下

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

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

https://i.stack.imgur.com/6JcDv.png

在 iOS 7 上运行时,一个快速的解决方法可能是在表格中添加一个 20 像素的空白标题。
@EricS:我已经有一个 UITableView 标题,它也在状态栏下方流动。
为什么不在 iOS 6 上使用自动布局指南?有用。

M
Mark A. Donohoe

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

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

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

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

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

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

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

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

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

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

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


仅供参考,选项 1(嵌入导航控制器)导致当您滚动表格时单元格在半透明状态栏后面可见。
@RyanR我也注意到了,但我认为在某些时候还可以。 Apple 在移动 Safari 的打开标签视图中做了同样的事情,标签将显示在状态栏下方。导航控制器解决方案是最简单的解决方法,我支持它。然而,半透明的状态栏是一个愚蠢的想法。
当我从 tableview 向上拖动控件时,我从来没有遇到过状态栏。视图中没有可见的状态栏,不知道你在这里的意思......
选项 2 在 Xcode 5 中不再适用。所描述的操作(ctrl-drag)应该永远不会起作用,因为它归 Outlets 系统所有,但即使您手动拖动到左侧的场景树,顶部布局指南也不起作用(应该可以,AFAICT - 我相信这是 AutoLayout 中的另一个主要错误 :( :( )
@PrideChung 使用带有表格视图的标题时看起来很愚蠢,标题保持固定在顶部,元素将消失在后面 - 并在透明状态栏后面重新出现......
J
Jay Lindelycke

如果您以编程方式执行操作并且使用没有 UINavigationControllerUITableViewController,那么最好的办法是在 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 仍会滚动到状态栏后面,但滚动到顶部时不会在状态栏下方。


您可以添加对操作系统版本 > 7 的检查并支持较旧的操作系统(这些没有插图)。否则,这对我的目的很有效。
硬编码高度值不是最好的主意。
是的,请改用 topLayoutGuide 长度。
我会使用 UIApplication.sharedApplication.statusBarFrame.size.height 而不是 20。
这些天已更新为 UIApplication.shared.statusBarFrame.size.height 。
S
Stunner

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

屏幕顶部没有导航栏(表格视图遇到状态栏)

表格视图不可滚动

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

原帖

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

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


有趣...我可以在我的项目中这样称呼它,没有任何问题...我可能有一个比你更简单的视图布局结构。你的建议是正确的,我会在我的答案中做出改变。
当我旋转我的应用程序时,我碰巧偶然发现了这个问题。如果您禁用了旋转,您可能不会遇到问题。
我的项目中没有启用旋转,我遇到了这个问题,但是,是的,仍然是一个好点。
对于任何实现自己的容器控制器的人来说,这是调整状态或导航栏重叠的正确方法!
如果您更改原点,但不更改视图边界的高度,屏幕底部边缘是否会按照您更改原点的量来裁剪底部? (因此无法看到最后几行像素)
E
ErikAGriffin

添加到最佳答案:

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

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

将一个空白的 ViewController 拖到情节提要上。将一个 UITableView 对象拖到视图中。 (不是 UITableViewController)。使用蓝色布局指南将其放置在最中心。

https://i.stack.imgur.com/1MUxA.png

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

https://i.stack.imgur.com/bdqtv.png

创建 UIViewController 的自定义子类,并添加 协议。不要忘记在 Identity Inspector 中将 Storyboard 的 ViewController 设置为此类。在您的实现文件中为您的 TableView 创建一个插座,并将其命名为“tableView”

https://i.stack.imgur.com/QraFO.png

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

https://i.stack.imgur.com/uoxoL.png

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

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

https://i.stack.imgur.com/RmFgN.png

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

https://i.stack.imgur.com/ECOJ6.png

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

https://i.stack.imgur.com/qsWRy.png

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


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


将 <= 切换为 > 并删除空的 if 块
viewDidLayoutSubviews 读取 self.topLayoutGuide.length 会搞砸子视图的布局。
@OLzh 按照您的描述进行操作, self.tableView 无法滚动。
P
Pau Ballada

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


唉,对我没用。完全默认的 UITableViewController 仍然与状态栏重叠。我不认为状态栏算作顶栏。只是导航栏和标签栏。
唯一对我有用的解决方案,ty。 (请注意,您必须在 IB 的状态栏下“缩短”表视图并更新约束)。
使用 UITableViewController 在 Xcode 8 上为我工作。
u
uplearned.com

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

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

这里不允许swift吗?
唯一对我有用的解决方案,不会让我创建 UIVIewController
这不太理想,因为它将顶部插图保持在 20,即使在 ios8 中没有默认状态栏的横向中也是如此
这个变体可以很好地处理我的任何配置:- (void)viewDidLayoutSubviews { if (self.tableView.contentInset.top != self.topLayoutGuide.length) { self.tableView.contentInset = UIEdgeInsetsMake(self.topLayoutGuide.length, 0.0, 0.0, 0.0); } }
D
David T

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

https://i.stack.imgur.com/NcxZF.png


最简单、最快、最简单、最安全?解决方案。不知道为什么与其他所有内容相比,它的赞成票如此之少。
E
Elijah

这将为 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
    }
}

H
Hot Licks

我不知道它是如何 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 来全局执行此操作。

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


b
bhr

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

干杯,本


W
Wesh RaphLola

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


P
Phong Le

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


l
lilislilit

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


M
MaxEcho

我已经为 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;
}

q
qix

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

S
Sam T

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

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

分享和享受...


f
fengd

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

https://i.stack.imgur.com/sJdQZ.png


“模拟指标”仅适用于在 Xcode 中查看您的创作,而不适用于现实。 [见:stackoverflow.com/questions/16279379/…
J
Jack Bellis

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,并且效果很好。


s
sfr14

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


这是在 iOS 8 中对我有用的唯一答案!
T
Tobi Nary
override func viewDidLoad() {
 // your code

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

D
Darkwonder

这是一个 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)。


D
DareDevil

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

https://i.stack.imgur.com/VewVs.png


L
Lee Irvine

对于像我这样不想将 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
}

N
NSCoder

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

https://i.stack.imgur.com/jBnU1.png


p
phnix

查看所有解决方案:我的项目只是使用 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;
    }
}

帮助这个工作。


C
Community

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

编辑

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


不幸的是,放下框架并不会改变它。
有什么不好的?表格视图不向下移动?
是的,它保持在同一个位置。我在 viewWillAppearviewDidLoad 中都尝试过 self.view.frameself.tableView.frame。为了安全起见,我还设置了 setContentNeedsDisplay 来强制重绘。
是否启用了自动布局?
是的,它是自动布局和故事板。