Autolayout + constraints for dynamic table height 基于总行数
Autolayout + constraints for dynamic table height based on total rows
首先这与动态单元格的高度无关。所以不要混淆了。
我有一个场景,我创建了三张卡片
- 详细信息卡片:显示位置的具体详细信息
- 图表卡片:根据选择显示不同的图表
- 更多详情卡片:卡片显示更多详情
以下是上述卡片的屏幕:
查看以上屏幕的层次结构:
- 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}]];
第三次添加TableView
到CustomView
:
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
中将其删除。
首先这与动态单元格的高度无关。所以不要混淆了。
我有一个场景,我创建了三张卡片
- 详细信息卡片:显示位置的具体详细信息
- 图表卡片:根据选择显示不同的图表
- 更多详情卡片:卡片显示更多详情
以下是上述卡片的屏幕:
查看以上屏幕的层次结构:
- 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}]];
第三次添加TableView
到CustomView
:
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
中将其删除。