是啥导致两个具有相同自动布局约束的 UITableViewCell 表现不同?

Posted

技术标签:

【中文标题】是啥导致两个具有相同自动布局约束的 UITableViewCell 表现不同?【英文标题】:What causes two UITableViewCells with the same autolayout constraints to behave differently?是什么导致两个具有相同自动布局约束的 UITableViewCell 表现不同? 【发布时间】:2016-11-21 19:36:19 【问题描述】:

我正在使用表格中的AFCollectionView,但它没有像我预期的那样呈现。为了调试问题,我创建了另一个具有所需布局的自定义表格单元格,并将其放入 AFCollectionView 单元格中。集合视图单元格仍未正确呈现。

这两个单元都是在没有 xib 或情节提要的情况下构建的,因此我正在努力尝试调试自动布局控制台问题。我知道 UICollectionView 比 UIView 更复杂,但鉴于显示的问题,我什至不确定从哪里开始尝试进行更改。

两个单元格都有以下从 - (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier 方法内部调用的 updateConstraints 方法。

    [self updateConstraints];
    return self;


- (void)updateConstraints
    [super updateConstraints];

    //Create local versions of the ivars
    UILabel *titleLabelP = self.titleLabel;
    UIView *bottomViewP = self.collectionView;
    NSNumber *bottomViewHeightP = [NSNumber numberWithInteger:self.bottomViewHeight];


    //Build the visual constraints
    NSDictionary *views = NSDictionaryOfVariableBindings(titleLabelP, bottomViewP);
    NSDictionary *metrics = @ @"padding" : @8.0, @"viewHeight": bottomViewHeightP ;

    // title and bottom view fill the width of the superview (cell content view)
    [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-padding-[titleLabelP]-padding-|" options:0 metrics:metrics views:views]];
    [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-padding-[bottomViewP]-padding-|" options:0 metrics:metrics views:views]];
    // title and bottom view are setup vertically with 8px of padding between.  The cell should expand to fit the full size of the bottom view.
    [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-padding-[titleLabelP]-padding-[bottomViewP(viewHeight)]-padding-|" options:0 metrics:metrics views:views]];


自动布局问题的控制台日志:

2016-11-21 14:19:06.423003 AutoLayoutTableCellTest[71645:4731377] [Warning] Warning once only: Detected a case where constraints ambiguously suggest a height of zero for a tableview cell's content view. We're considering the collapse unintentional and using standard height instead.
2016-11-21 14:19:06.425136 AutoLayoutTableCellTest[71645:4731377] [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. 
    (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints) 
(
    "<NSAutoresizingMaskLayoutConstraint:0x608000096710 h=--& v=--& UITableViewCellContentView:0x7fb87ac1a770.midY == 22.25   (active)>",
    "<NSAutoresizingMaskLayoutConstraint:0x6080000966c0 h=--& v=--& UITableViewCellContentView:0x7fb87ac1a770.height == 44.5   (active)>",
    "<NSLayoutConstraint:0x608000095860 V:|-(8)-[UILabel:0x7fb87ac1b670'CURRENT INDEXPATH ROW: 1']   (active, names: '|':AFTableViewCell:0x7fb87b050400'CellIdentifier' )>",
    "<NSLayoutConstraint:0x608000095900 AFIndexedCollectionView:0x7fb87b051000.height == 150   (active)>",
    "<NSLayoutConstraint:0x608000095950 V:[AFIndexedCollectionView:0x7fb87b051000]-(8)-|   (active, names: '|':UITableViewCellContentView:0x7fb87ac1a770 )>",
    "<NSLayoutConstraint:0x608000095fe0 V:[UILabel:0x7fb87ac1b670'CURRENT INDEXPATH ROW: 1']-(8)-[AFIndexedCollectionView:0x7fb87b051000]   (active)>",
    "<NSAutoresizingMaskLayoutConstraint:0x608000095180 h=-&- v=--& 'UIView-Encapsulated-Layout-Top' AFTableViewCell:0x7fb87b050400'CellIdentifier'.minY == 0   (active, names: '|':UITableViewWrapperView:0x7fb87b03b800 )>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x608000095fe0 V:[UILabel:0x7fb87ac1b670'CURRENT INDEXPATH ROW: 1']-(8)-[AFIndexedCollectionView:0x7fb87b051000]   (active)>

Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.
2016-11-21 14:19:06.425934 AutoLayoutTableCellTest[71645:4731377] [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. 
    (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints) 
(
    "<NSAutoresizingMaskLayoutConstraint:0x608000096710 h=--& v=--& UITableViewCellContentView:0x7fb87ac1a770.midY == 22.25   (active)>",
    "<NSAutoresizingMaskLayoutConstraint:0x6080000966c0 h=--& v=--& UITableViewCellContentView:0x7fb87ac1a770.height == 44.5   (active)>",
    "<NSLayoutConstraint:0x608000095860 V:|-(8)-[UILabel:0x7fb87ac1b670'CURRENT INDEXPATH ROW: 1']   (active, names: '|':AFTableViewCell:0x7fb87b050400'CellIdentifier' )>",
    "<NSLayoutConstraint:0x6080000958b0 V:[UILabel:0x7fb87ac1b670'CURRENT INDEXPATH ROW: 1']-(8)-[AFIndexedCollectionView:0x7fb87b051000]   (active)>",
    "<NSLayoutConstraint:0x608000095900 AFIndexedCollectionView:0x7fb87b051000.height == 150   (active)>",
    "<NSLayoutConstraint:0x608000095950 V:[AFIndexedCollectionView:0x7fb87b051000]-(8)-|   (active, names: '|':UITableViewCellContentView:0x7fb87ac1a770 )>",
    "<NSAutoresizingMaskLayoutConstraint:0x608000095180 h=-&- v=--& 'UIView-Encapsulated-Layout-Top' AFTableViewCell:0x7fb87b050400'CellIdentifier'.minY == 0   (active, names: '|':UITableViewWrapperView:0x7fb87b03b800 )>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x6080000958b0 V:[UILabel:0x7fb87ac1b670'CURRENT INDEXPATH ROW: 1']-(8)-[AFIndexedCollectionView:0x7fb87b051000]   (active)>

Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.

我已经把示例项目放到了github上@https://github.com/propstm/AutoLayoutTableCellTest

使用 COLLECTIONVIEW 编辑以显示单元格的初始化:

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier

    if (!(self = [super initWithStyle:style reuseIdentifier:reuseIdentifier])) return nil;

    UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
    layout.sectionInset = UIEdgeInsetsMake(10, 10, 9, 10);
    layout.itemSize = CGSizeMake(100, 100);

    layout.scrollDirection = UICollectionViewScrollDirectionVertical;
    self.collectionView = [[AFIndexedCollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout];
    [self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:CollectionViewCellIdentifier];
    [self.collectionView setTranslatesAutoresizingMaskIntoConstraints:FALSE];
    self.collectionView.backgroundColor = [UIColor whiteColor];
    self.collectionView.showsHorizontalScrollIndicator = NO;
    [self.contentView addSubview:self.collectionView];
    if(!self.titleLabel)
        self.titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(16, 8, self.frame.size.width-8, 20)];
        [self.titleLabel setTranslatesAutoresizingMaskIntoConstraints:FALSE];
        UIFont *boldFont = [UIFont fontWithName:@".SFUIText-Bold" size:16.0f];
        [self.titleLabel setFont:boldFont];
        [self addSubview:self.titleLabel];
    

    self.bottomViewHeight = 150;

    [self updateConstraints];
    return self;

【问题讨论】:

【参考方案1】:

通过以下更改,我能够消除这些自动布局警告:

在您的AFTableViewCell-initWithStyle:reuseIdentifier: 方法中,在返回之前,将单元格的contentViewtranslatesAutoresizingMaskIntoConstraints 属性设置为NO。 将标题标签添加到单元格的内容视图,而不是单元格本身。

这会导致出现新的警告:

[Warning] Warning once only: Detected a case where constraints ambiguously suggest a height of zero for a tableview cell's content view. We're considering the collapse unintentional and using standard height instead.

但是,布局似乎更接近您的预期。

【讨论】:

【参考方案2】:

每当您以编程方式创建视图并设置自动布局约束时,您必须在添加约束的视图上设置translatesAutoresizingMaskIntoConstraints = false。如果没有,自动调整掩码将转换为自动布局约束。

在这种情况下,您需要添加类似:

self.titleLabel.translateAutoresizingMaskIntoConstraints = false
self.collectionView.translateAutoresizingMaskIntoConstraints = false

已添加

根据您添加的日志,collectionView 的高度为 150,但 contentView 的高度小于该高度。您必须返回正确的高度UITableViewCell

【讨论】:

我已经在单元格的 init 方法中将那部分放在上面。我也将该代码添加到帖子中。我尝试将 NO 替换为 FALSE,仍然没有解决方案。 我正在使用估计的行高。 titleLabel 的高度为 20,collectionView 的高度为 150,因此在我的垂直约束下,我希望自动调整大小的高度约为 200。 你也有填充物。返回所有高度和填充总和的确切高度

以上是关于是啥导致两个具有相同自动布局约束的 UITableViewCell 表现不同?的主要内容,如果未能解决你的问题,请参考以下文章

iOS 以编程方式生成的视图具有隐藏的约束,导致与自动布局发生冲突

iOS自动布局两个UIView具有相等的宽度

具有自动布局的 UITableviewCell 约束失败

相同的自动布局约束在纵向和横向中表现不同

在其他两个之间垂直居中视图

Interface Builder 对 UIScrollView 的正确约束是啥?来自 IB 的纯自动布局