我正在尝试将自动布局合并到我的UITableViewHeaderFooterView子类中。这个课程非常基础,只有两个标签。这是完整的子类:
@implementation MBTableDetailStyleFooterView
static void MBTableDetailStyleFooterViewCommonSetup(MBTableDetailStyleFooterView *_self) {
UILabel *rightLabel = [[UILabel alloc] init];
_self.rightLabel = rightLabel;
rightLabel.translatesAutoresizingMaskIntoConstraints = NO;
[_self.contentView addSubview:rightLabel];
UILabel *leftLabel = [[UILabel alloc] init];
_self.leftLabel = leftLabel;
leftLabel.translatesAutoresizingMaskIntoConstraints = NO;
[_self.contentView addSubview:leftLabel];
NSDictionary *views = NSDictionaryOfVariableBindings(rightLabel, leftLabel);
NSArray *horizontalConstraints = [NSLayoutConstraint constraintsWithVisualFormat:@"|-10-[leftLabel]-(>=10)-[rightLabel]-10-|" options:0 metrics:nil views:views];
[_self.contentView addConstraints:horizontalConstraints];
// center views vertically in super view
NSLayoutConstraint *leftCenterYConstraint = [NSLayoutConstraint constraintWithItem:leftLabel attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:_self.contentView attribute:NSLayoutAttributeCenterY multiplier:1 constant:0];
[_self.contentView addConstraint:leftCenterYConstraint];
NSLayoutConstraint *rightCenterYConstraint = [NSLayoutConstraint constraintWithItem:rightLabel attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:_self.contentView attribute:NSLayoutAttributeCenterY multiplier:1 constant:0];
[_self.contentView addConstraint:rightCenterYConstraint];
// same height for both labels
NSLayoutConstraint *sameHeightConstraint = [NSLayoutConstraint constraintWithItem:leftLabel attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:rightLabel attribute:NSLayoutAttributeHeight multiplier:1 constant:0];
[_self.contentView addConstraint:sameHeightConstraint];
}
+ (BOOL)requiresConstraintBasedLayout {
return YES;
}
- (id)initWithReuseIdentifier:(NSString *)reuseIdentifier {
self = [super initWithReuseIdentifier:reuseIdentifier];
MBTableDetailStyleFooterViewCommonSetup(self);
return self;
}
@end
此类在tableView的第一部分中用作页脚,包含2个部分。第一部分包含动态项目。第二部分只有一行,用于向第一部分添加新项目。
如果第一部分中没有项目,我隐藏了footerView。因此,当我添加第一个新项目时,我必须重新加载该部分,以便显示footerView。执行所有这些操作的代码如下所示:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:YES];
if (indexPath.section == 1) {
BOOL sectionNeedsReload = ([self.data count] == 0); // reload section when no data (and therefor no footer) was present before the add
[self.data addObject:[NSDate date]];
NSIndexPath *newIndexPath = [NSIndexPath indexPathForRow:[self.data count]-1 inSection:0];
if (sectionNeedsReload) {
[self.tableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationAutomatic];
}
else {
[self.tableView insertRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
}
[self configureFooter:(MBTableDetailStyleFooterView *)[tableView footerViewForSection:0] forSection:0];
}
}
- (void)configureFooter:(MBTableDetailStyleFooterView *)footer forSection:(NSInteger)section {
footer.leftLabel.text = @"Total";
footer.rightLabel.text = [NSString stringWithFormat:@"%d", [self.data count]];
}
- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section {
MBTableDetailStyleFooterView *footer = nil;
if (section == 0 && [self.data count]) {
footer = [tableView dequeueReusableHeaderFooterViewWithIdentifier:@"Footer"];
[self configureFooter:footer forSection:section];
}
return footer;
}
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
CGFloat height = 0;
if (section == 0 && [self.data count]) {
height = 20.0f;
}
return height;
}
没什么好看的。但是,只要在我的tableView上调用reloadSections:withRowAnimations:
,就会抛出异常,因为它“无法同时满足约束条件。”。
tableView在某处向我的页脚添加了一个已翻译的自动调整大小屏幕约束。
(
"<NSLayoutConstraint:0x718a1f0 H:[UILabel:0x7189130]-(10)-| (Names: '|':_UITableViewHeaderFooterContentView:0x7188df0 )>",
"<NSLayoutConstraint:0x7189e30 H:[UILabel:0x71892c0]-(>=10)-[UILabel:0x7189130]>",
"<NSLayoutConstraint:0x718a0a0 H:|-(10)-[UILabel:0x71892c0] (Names: '|':_UITableViewHeaderFooterContentView:0x7188df0 )>",
"<NSAutoresizingMaskLayoutConstraint:0x7591ab0 h=--& v=--& H:[_UITableViewHeaderFooterContentView:0x7188df0(0)]>"
)
当我通过调用reloadSections:withRowAnimations:
替换reloadData
时,没有添加自动调整遮罩约束,一切正常。
有趣的是,异常告诉我它试图打破约束<NSLayoutConstraint:0x7189e30 H:[UILabel:0x71892c0]-(>=10)-[UILabel:0x7189130]>
但是当我在后续调用configureFooter:forSection:
时记录约束时,这个约束仍然存在,但自动调整大小掩码约束已经消失
约束正是我设置的那些。
(
"<NSLayoutConstraint:0x718a0a0 H:|-(10)-[UILabel:0x71892c0] (Names: '|':_UITableViewHeaderFooterContentView:0x7188df0 )>",
"<NSLayoutConstraint:0x7189e30 H:[UILabel:0x71892c0]-(>=10)-[UILabel:0x7189130]>",
"<NSLayoutConstraint:0x718a1f0 H:[UILabel:0x7189130]-(10)-| (Names: '|':_UITableViewHeaderFooterContentView:0x7188df0 )>",
"<NSLayoutConstraint:0x718a3f0 UILabel:0x71892c0.centerY == _UITableViewHeaderFooterContentView:0x7188df0.centerY>",
"<NSLayoutConstraint:0x718a430 UILabel:0x7189130.centerY == _UITableViewHeaderFooterContentView:0x7188df0.centerY>",
"<NSLayoutConstraint:0x718a4b0 UILabel:0x71892c0.height == UILabel:0x7189130.height>"
)
这个自动调整大小掩码约束来自哪里?它去哪儿了?
我错过了什么吗?我第一次看到汽车布局就像一周前,所以这是完全可能的。
答案 0 :(得分:23)
在UITableViewHeaderFooterView子类中放置以下代码。
- (void)setFrame:(CGRect)frame {
if (frame.size.width == 0) {
return;
}
[super setFrame:frame];
}
<强>解释强>
tableview处理标题视图的布局,它通过手动操作框架来实现(即使打开了autolayout也是如此)。
如果检查页眉/页脚视图上的宽度约束,则有两个,一个包含在超视图(表视图)中,宽度为一个,页眉/页脚视图中包含一个宽度。 / p>
超级视图中包含的约束是NSAutoresizingMaskLayoutConstraint,它是tableview依赖于操作标题的帧的赠品。在标题视图上将translatesAutoresizingMaskIntoConstraints切换为NO会有效地破坏它的外观,这是另一种消除。
看来在某些情况下,这些页眉/页脚视图的帧会更改为宽度为零,对我而言,插入行并重新使用标题视图时。我的猜测是,在UITableView代码的某处,即使您没有使用动画,也可以通过以零宽度启动帧来制作动画。
此解决方案应该运行良好,不应影响滚动性能。
答案 1 :(得分:7)
上周我跑到了这里。
我消除警告的方式是change my required constraints to have a priority of 999。这是一个解决方法而不是修复,但它确实可以解决在布局期间抛出,捕获和记录的异常。
建议是set estimatedRowHeight
。我试图设置estimatedSectionHeaderHeight
,但这并没有帮助。设置一个estimatedSectionFooterHeight
创建的空页脚,我不想要它们,这有点奇怪。
我还尝试在页眉页脚视图及其内容视图中设置translatesAutoresizingMaskIntoConstraints = NO;
。既没有摆脱警告,也没有导致布局彻底破坏。
答案 2 :(得分:3)
我在contentView中只有一个额外的标签也有类似的问题。尝试插入
static void MBTableDetailStyleFooterViewCommonSetup(MBTableDetailStyleFooterView *_self) {
_self.contentView.translatesAutoresizingMaskIntoConstraints = NO
[...]
}
在MBTableDetailStyleFooterViewCommonSetup
函数的第一行。对我来说,这与reloadSections:withRowAnimations:
一起使用。
<强>更新强>
我还为contentView添加了一个新约束来使用所有宽度:
NSArray *horizontalConstraints = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[contentView]|"
options:0
metrics:nil
views:@{@"contentView" : _self.contentView}];
[_self.contentView.superview addConstraints:horizontalConstraints];
答案 3 :(得分:2)
太奇怪了!感谢@josh-bernfield,这是我为iOS 11.3写的:
override var frame: CGRect {
get {
return super.frame
}
set {
if newValue.width == 0 { return }
super.frame = newValue
}
}
答案 4 :(得分:1)
令人讨厌的是,UITableViewHeaderFooterView看起来并不像常量约束,例如。
| -10- [图] -10- |
我猜是因为在创建时视图的宽度为零,并且不能满足约束条件,在这种情况下需要至少20px的宽度。
对我来说,解决这个问题的方法是将我的常量约束改为
| - (小于= 10) - [图] - (小于= 10) - |
哪个应该满足零宽度内容,并且在调整大小时应该给出所需的余量。
答案 5 :(得分:1)
在iOS 11中,我只是 无法正确显示UITableViewHeaderFooterView
。
问题在于,当UITableViewHeaderFooterView
认为它的边界是空的时,我正在设置我的约束,所以它总会引起冲突。
这是解决方案
override func layoutSubviews() {
super.layoutSubviews()
guard bounds != CGRect.zero else {
return
}
makeConstraints()
}
答案 6 :(得分:0)
我没有在页脚本身看到你在哪里调用translatesAutoresizingMaskIntoConstraints = NO。你应该在创建时这样做吗?
- (id)initWithReuseIdentifier:(NSString *)reuseIdentifier {
self = [super initWithReuseIdentifier:reuseIdentifier];
self.translatesAutoresizingMaskIntoConstraints = NO;
MBTableDetailStyleFooterViewCommonSetup(self);
return self;
}
答案 7 :(得分:0)
我有一个类似的问题,在contentView中只有一个UILabel,我使用了Masonry:
findButton
然后我收到了警告:
_titleLabel = ({
UILabel *label = [MLBUIFactory labelWithType:MALabelTypeB];
[self.contentView addSubview:label];
[label mas_makeConstraints:^(MASConstraintMaker */make) {
make.centerY.equalTo(self.contentView);
make.left.equalTo(self.contentView).offset(8);
make.right.equalTo(self.contentView).offset(-8);
}];
label;
});
所以我尝试设置(
"<MASLayoutConstraint:0x1742b2c60 UILabel:0x124557ee0.left == _UITableViewHeaderFooterContentView:0x12454c640.left + 8>",
"<MASLayoutConstraint:0x1742b3080 UILabel:0x124557ee0.right == _UITableViewHeaderFooterContentView:0x12454c640.right - 8>",
"<NSLayoutConstraint:0x174280780 _UITableViewHeaderFooterContentView:0x12454c640.width == 0>"
)
Will attempt to recover by breaking constraint
<MASLayoutConstraint:0x1742b3080 UILabel:0x124557ee0.right == _UITableViewHeaderFooterContentView:0x12454c640.right - 8>
,但它对我没有用,所以我专注于警告信息,我很困惑,为什么左边约束可以工作但是正确,当我看到self.translatesAutoresizingMaskIntoConstraints = NO;
,我发现,也许这就是为什么正确的约束是破坏约束,然后我改变了代码:
_UITableViewHeaderFooterContentView:0x12454c640.width == 0
我用宽度约束替换了右边的约束,警告消失了。
还有其他方法可以让警告消失:_titleLabel = ({
UILabel *label = [MLBUIFactory labelWithType:MALabelTypeB];
[self.contentView addSubview:label];
[label mas_makeConstraints:^(MASConstraintMaker */make) {
make.centerY.equalTo(self.contentView);
make.left.equalTo(self.contentView).offset(8);
make.width.equalTo(@(SCREEN_WIDTH - 16));
}];
label;
});
,但标签的框架是错误的。
答案 8 :(得分:0)
需要更新docker run -v volumename:/data -it my_image
$query->select('id, CONCAT_WS(' ', Name, Surname) as name')
->from('customer')
->where('CONCAT_WS(' ', Name, Surname) LIKE "%' . $search .'%"')
->limit(10)
,警告消失了。这可能类似于Auto layout constraints issue on iOS7 in UITableViewCell
contentView
答案 9 :(得分:0)
我认为我们可以放心地忽略控制台警告。
我怀疑控制台日志是由表视图布局过程的某些中间状态引起的。
当我添加具有自动布局内容的页脚剖面视图时,在控制台中也会收到无法满足的约束警告。
从下面的日志中,引起问题的约束应该为_UITableViewHeaderFooterContentView:0x7ff2115778d0.height == 0
2018-08-23 16:01:27.036159-0700 Attendee[45370:2760310] [LayoutConstraints] Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don't want.
Try this:
(1) look at each constraint and try to figure out which you don't expect;
(2) find the code that added the unwanted constraint or constraints and fix it.
(
"<NSLayoutConstraint:0x60000029d7e0 UILayoutGuide:0x6000003b98a0'UIViewLayoutMarginsGuide'.bottom == UIButton:0x7ff2115770a0.bottom + 20 (active)>",
"<NSLayoutConstraint:0x604000481d60 UILayoutGuide:0x6000003b98a0'UIViewLayoutMarginsGuide'.top == UIButton:0x7ff211576790'Forgot password?'.top (active)>",
"<NSLayoutConstraint:0x604000481c70 UIButton:0x7ff211576790'Forgot password?'.bottom == UIButton:0x7ff2115770a0.top - 8 (active)>",
"<NSLayoutConstraint:0x60000029d600 'UIView-bottomMargin-guide-constraint' V:[UILayoutGuide:0x6000003b98a0'UIViewLayoutMarginsGuide']-(8)-| (active, names: '|':_UITableViewHeaderFooterContentView:0x7ff2115778d0 )>",
"<NSLayoutConstraint:0x60000029da10 'UIView-Encapsulated-Layout-Height' _UITableViewHeaderFooterContentView:0x7ff2115778d0.height == 0 (active)>",
"<NSLayoutConstraint:0x60000029d560 'UIView-topMargin-guide-constraint' V:|-(8)-[UILayoutGuide:0x6000003b98a0'UIViewLayoutMarginsGuide'] (active, names: '|':_UITableViewHeaderFooterContentView:0x7ff2115778d0 )>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x60000029d7e0 UILayoutGuide:0x6000003b98a0'UIViewLayoutMarginsGuide'.bottom == UIButton:0x7ff2115770a0.bottom + 20 (active)>
如果我覆盖页脚视图的layoutSubviews
,以转储影响垂直布局的约束:
override func layoutSubviews() {
super.layoutSubviews()
print("after layout")
dump(contentView.constraintsAffectingLayout(for: .vertical))
}
我得到以下输出:
▿ 2 elements
- <NSLayoutConstraint:0x600000297110 'UIView-Encapsulated-Layout-Height' _UITableViewHeaderFooterContentView:0x7ffc22d88c20.height == 101 (active)> #0
- super: NSObject
- <NSAutoresizingMaskLayoutConstraint:0x6000002971b0 h=--& v=--& 'UIView-Encapsulated-Layout-Top' _UITableViewHeaderFooterContentView:0x7ffc22d88c20.minY == 0 (active, names: '|':Attendee.SearchFormButtonFooter:0x7ffc22d20da0 )> #1
- super: NSLayoutConstraint
- super: NSObject
没有明确的布局约束将内容视图的高度设置为0。这可能只是内容视图的自动调整蒙版,从而导致UITableView布局过程的某些中间状态出现问题。
答案 10 :(得分:0)
我遇到了这个问题,发现的最佳解决方案是在init中设置默认框架。该框架无论如何都会改变,但是对于在0,0,0,0框架上打破的约束很有用。
override init(reuseIdentifier: String?) {
super.init(reuseIdentifier: reuseIdentifier)
frame = CGRect(x: 0, y: 0, width: 100, height: 100)
//... setup constraints...
}