Autolayout + constraints for dynamic table height 基于总行数

Autolayout + constraints for dynamic table height based on total rows

首先这与动态单元格的高度无关。所以不要混淆了。

我有一个场景,我创建了三张卡片

  1. 详细信息卡片:显示位置的具体详细信息
  2. 图表卡片:根据选择显示不同的图表
  3. 更多详情卡片:卡片显示更多详情

以下是上述卡片的屏幕:

查看以上屏幕的层次结构:

  • Controller
    • ScrollView
    • Card-1
    • Card-2
    • Card-3 <---- We are interested in this card
      • Custom View
        • TableView

所以我在这里展示了最后一张卡片的约束,以上所有卡片都完美无缺!并且没有约束歧义或警告。

让我们看一下代码:

先在ScrollView中加上Card-3这里chartBox是Card-2,bottomBox是Card-3

[self.scrollView addConstraints:[NSLayoutConstraint
                                 constraintsWithVisualFormat:@"V:[chartBox(200)]-(10)-[bottomBox]"
                                 options:0
                                 metrics:nil
                                 views:@{@"bottomBox" : self.bottomBox, @"chartBox" : self.chartBox}]];

// Below constraint pin to increase content-size
[self.scrollView addConstraints:[NSLayoutConstraint
                                constraintsWithVisualFormat:@"V:[bottomBox]-(10)-|"
                                options:0
                                metrics:nil
                                views:@{@"bottomBox" : self.bottomBox}]];

[self.scrollView addConstraints:[NSLayoutConstraint
                                constraintsWithVisualFormat:@"H:[bottomBox]-(10)-|"
                                options:0
                                metrics:nil
                                views:@{@"bottomBox" : self.bottomBox}]];

其次在Card-3中添加CustomView这里bluePrintView是CustomView

_bluePrintView = [[BluePrintView alloc] init];
self.bluePrintView.translatesAutoresizingMaskIntoConstraints = NO;
[self.bottomBox addSubview:self.bluePrintView];

[self.bottomBox addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[bluePrintView]|" options:0 metrics:nil views:@{@"bluePrintView":self.bluePrintView}]];
[self.bottomBox addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[bluePrintView]|" options:0 metrics:nil views:@{@"bluePrintView":self.bluePrintView}]];

CGRect screenRect = [[UIScreen mainScreen] bounds];
CGFloat screenWidth = screenRect.size.width - 20;
NSDictionary *metrices = @{@"width" : [NSNumber numberWithFloat:screenWidth]};
[self.scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(10)-[bottomBox(width)]" options:0 metrics:metrices views:@{ @"bottomBox": self.bottomBox}]];

第三次添加TableViewCustomView

self.tableView.tableFooterView = [[UIView alloc] init];

[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[tableView]|" options:0 metrics:nil views:@{@"tableView":self.tableView}]];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[tableView]|" options:0 metrics:nil views:@{@"tableView":self.tableView}]];

// Height constraint
CGFloat viewHeight = self.bounds.size.height;
self.tableHeightConstraint = [NSLayoutConstraint constraintWithItem:self.tableView
                                                          attribute:NSLayoutAttributeHeight
                                                          relatedBy:NSLayoutRelationEqual
                                                             toItem:nil
                                                          attribute:NSLayoutAttributeNotAnAttribute
                                                         multiplier:1.0
                                                           constant:viewHeight];
[self addConstraint:self.tableHeightConstraint];

[self.tableView addObserver:self forKeyPath:@"contentSize" options:0 context:NULL];

在观察者方法中,我将更新 tableHeightConstraint 约束。

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    self.tableHeightConstraint.constant = self.tableView.contentSize.height;
    [self.tableView setNeedsLayout];
    [self.tableView layoutIfNeeded];
}

在尝试了所有的可能性之后,这里就结束了。约束警告。

(
    "<NSLayoutConstraint:0x7fbeb1e7e8e0 V:|-(0)-[UITableView:0x7fbeb2843000]   (Names: '|':BluePrintView:0x7fbeb1e7ac30 )>",
    "<NSLayoutConstraint:0x7fbeb1e7e700 V:[UITableView:0x7fbeb2843000]-(0)-|   (Names: '|':BluePrintView:0x7fbeb1e7ac30 )>",
    "<NSLayoutConstraint:0x7fbeb1e7e9b0 V:[UITableView:0x7fbeb2843000(480)]>",
    "<NSLayoutConstraint:0x7fbeb1e81a20 '_UITemporaryLayoutHeight' V:[BluePrintView:0x7fbeb1e7ac30(0)]>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x7fbeb1e7e700 V:[UITableView:0x7fbeb2843000]-(0)-|   (Names: '|':BluePrintView:0x7fbeb1e7ac30 )>

我通过从 [tableView] 中删除 | 行解决了这些警告(通过删除对 superView 的底部约束),但是 tableView 没有获得所需的高度。

知道如何在没有任何约束警告的情况下获得完整的 tableView 高度。

P.S。所有视图都是由代码创建的,没有 XIB 没有 Storyboard 布局。 iOS9.2

我在您的约束设置中没有发现任何错误。

您可能会看到此 UITemporaryLayoutHeight 约束,因为您添加了 contentSize 观察器([self.tableView addObserver:self forKeyPath:@"contentSize" options:0 context:NULL] ) 在您的视图生命周期中过早,这会触发 [self.tableView layoutIfNeeded].

尝试在视图控制器的 viewDidLoad 中添加观察者,在 dealloc 中将其删除;或者在您的 viewWillAppear 中,例如在 viewWillDisappear 中将其删除。