使用自动布局将视图定位在 tableview 的顶部

Posted

技术标签:

【中文标题】使用自动布局将视图定位在 tableview 的顶部【英文标题】:Positioning a view on top of a tableview using Auto Layout 【发布时间】:2014-09-01 19:15:24 【问题描述】:

我的故事板中有一个表视图,它的类设置为我的UITableView 子类,名为SPSExplanationTableView。在 Interface Builder 中,此 tableview 上没有设置任何约束。

我正在尝试以编程方式创建一个 UIView,它显示在 tableview 的前面——which I know how to do(博客文章链接)——但它是使用自动布局来调整大小和定位的。这是我的代码:

#import "SPSExplanationTableView.h"

@interface SPSExplanationTableView()

@property (nonatomic, strong) UIView *explanationView;

@end

@implementation SPSExplanationTableView

- (void)awakeFromNib

    [super awakeFromNib];
    self.explanationView = [[UIView alloc] init];
    self.explanationView.translatesAutoresizingMaskIntoConstraints = NO;
    self.explanationView.backgroundColor = [UIColor blueColor];

    [self addSubview:self.explanationView];
    [self bringSubviewToFront:self.explanationView];

NSLayoutConstraint *heightConstraint = [NSLayoutConstraint constraintWithItem:self.explanationView
                                                                    attribute:NSLayoutAttributeHeight
                                                                    relatedBy:NSLayoutRelationEqual
                                                                       toItem:nil
                                                                    attribute:NSLayoutAttributeNotAnAttribute
                                                                   multiplier:1.0f constant:150.0f];
[self.explanationView addConstraint:heightConstraint];

NSLayoutConstraint *widthConstraint = [NSLayoutConstraint constraintWithItem:self.explanationView
                                                                   attribute:NSLayoutAttributeWidth
                                                                   relatedBy:NSLayoutRelationEqual
                                                                      toItem:nil
                                                                   attribute:NSLayoutAttributeNotAnAttribute
                                                                  multiplier:1.0f constant:200.0f];
[self.explanationView addConstraint:widthConstraint];

NSLayoutConstraint *topConstraint = [NSLayoutConstraint constraintWithItem:self.explanationView
                                                                 attribute:NSLayoutAttributeCenterY
                                                                 relatedBy:NSLayoutRelationEqual
                                                                    toItem:self
                                                                 attribute:NSLayoutAttributeCenterY
                                                                multiplier:1.0f constant:0.0f];
[self addConstraint:topConstraint];

NSLayoutConstraint *leftConstraint = [NSLayoutConstraint constraintWithItem:self.explanationView
                                                                  attribute:NSLayoutAttributeCenterX
                                                                  relatedBy:NSLayoutRelationEqual
                                                                     toItem:self
                                                                  attribute:NSLayoutAttributeCenterX
                                                                 multiplier:1.0f constant:0.0f];
[self addConstraint:leftConstraint];

@end

当我运行应用程序时,它会因以下断言失败而崩溃:

*** -[SPSExplanationTableView layoutSublayersOfLayer:] 中的断言失败,
/SourceCache/UIKit_Sim/UIKit-2935.137/UIView.m:8794
*** 由于未捕获的异常“NSInternalInconsistencyException”而终止应用程序,原因:“自动布局仍然
执行 -layoutSubviews 后需要。 SPSExplanationTableView 的
-layoutSubviews 的实现需要调用 super.'

从字面上理解消息并覆盖 layoutSubviews 没有任何效果,即我仍然遇到同样的崩溃。

- (void)layoutSubviews

    [super layoutSubviews];

实现我想要实现的目标的正确方法是什么?


对于 Aubada Taljo,这是 Interface Builder 中的表格视图:


更新:我最终通过不使用自动布局解决了这个问题!我在我的 SPSExplanationTableView 类中覆盖了 layoutSubviews 方法,并将 explainView 的 center 属性设置为自身边界的中心,并对 y 轴位置进行了一些微调,使其看起来像我想要的那样。

【问题讨论】:

【参考方案1】:

这会崩溃,因为 UITableViews 不是为此而设计的。 UITableView 只关心它的单元格、标题,可能还有它的背景,并且它具有不使用自动布局的逻辑。因此,如果您尝试将其参与到它与任何子视图之间的任何约束计算中,它将崩溃,例如如果您在单元格和表格之间添加约束,这也会崩溃。

我建议你做的是添加一个包含你的表和你想要覆盖的视图的超级视图:

SuperviewWithConstraints
    |
    |-- YourTableViewWithConstraintsRelativeToSuperview
    |
    |-- YourOverlayWithConstraintsRelativeToSuperview

并在那里设置约束。然后将该超级视图作为您的视图控制器的视图。不过,您将不得不放弃使用 UITableViewController 作为控制类。

【讨论】:

【参考方案2】:

如果您愿意接受我的建议并让您的生活更轻松,只需转到 Interface Builder 中的情节提要并在表格视图上设置正确的约束,现在返回代码编辑器和拥有您的表格视图的 UIViewController ,在viewDidLoad中编写视图创建代码例如

UIView* someView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.tableView.frame.size.width, self.tableView.frame.size.height)];
[self.view addSubView someView];

我想这应该足以解决您的问题,现在如果您遇到任何问题,请将您的代码移动到 UIViewController 中的 viewDidLayoutSubViews

如果您需要更多详细信息,请告诉我,但我一直使用这种方式来创建动态控件。

【讨论】:

谢谢,但我不确定如何在 Interface Builder 中的 tableview 上设置正确的约束,因为那里不存在子视图。此外,我并不特别想用视图创建代码弄乱我的视图控制器。感觉我应该可以为此使用自包含的 tableview 类。 关键是您不必为子视图(someView)设置正确的约束,您只需在Interface Builder中为表视图设置正确的约束,上面的代码即可休息。此外,将视图添加为 UITableView 的子视图也不好,因为它不是为此而设计的,所以上面的代码会告诉你你想要什么 那么tableview的正确约束是什么? 能否给我看一张界面构建器中视图控制器的屏幕截图(包含 uitableview 的那个) 我已根据要求编辑了我的问题以包含屏幕截图。视图控制器是 UITableViewController 的子类。

以上是关于使用自动布局将视图定位在 tableview 的顶部的主要内容,如果未能解决你的问题,请参考以下文章

iOS - 以编程方式使用自动布局将 UIView 定位在超级视图的中心

TextView的自动高度,在tableView的单元格中使用autolayout

当 tableview 使用自动布局滚动时避免粘性标题视图

如何在 iOS 6 中使用具有多个子视图的现有自定义视图自动布局

如何以编程方式使用自动布局将活动指示器定位到其超级视图的中心?

使用自动布局和 SnapKit 进行相对定位