关于objective c:在UITableView上调整每个单元格的NSLayoutConstraint

Adjusting NSLayoutConstraint per cell on UITableView

我有一个UitableViewController,分组样式,带有一个自定义的UitableViewCell。在uiTableViewCell中,我有nslayoutConstraints,它在故事板(在原型单元上)中定义,用于指示uiImageView的大小和位置。这些nslayoutConstraints链接到uiTableViewCell子类的属性。

在子类UITableViewCell的-(void)layoutSubviews方法中,我尝试使用

1
self.topSpacingConstraint.constant = 0;

以每个单元为基础更改排列。

不过,这行代码调整了我所有单元格的约束。我不明白为什么,也不知道如何为单个单元格设置约束。

更新

这是uiTableViewCell子类的-(void)layoutSubviews方法的完整代码。self.topCellself.bottomCell是在配置单元时由uiTableViewController设置的属性。基于这些值,我尝试更新每个单元上图像的自动布局间距:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
- (void)layoutSubviews
{
    [super layoutSubviews];

    UIImage *mask;

    if (self.topCell && self.bottomCell) {
        self.imageSpacingTopConstraint.constant = 1;
        self.imageSpacingBottomConstraint.constant = 2;
        mask = MTDContextCreateRoundedMask(self.wineImage.bounds, 6.0, 0.0, 6.0, 0.0);
    } else if (self.topCell) {
        self.imageSpacingTopConstraint.constant = 1;
        self.imageSpacingBottomConstraint.constant = 0;
        mask = MTDContextCreateRoundedMask(self.wineImage.bounds, 6.0, 0.0, 0.0, 0.0);
    } else if (self.bottomCell) {
        self.imageSpacingTopConstraint.constant = 0;
        self.imageSpacingBottomConstraint.constant = 2;
        mask = MTDContextCreateRoundedMask(self.wineImage.bounds, 0.0, 0.0, 6.0, 0.0);
    } else {
        self.imageSpacingTopConstraint.constant = 0;
        self.imageSpacingBottomConstraint.constant = 0;
        mask = MTDContextCreateRoundedMask(self.wineImage.bounds, 0.0, 0.0, 0.0, 0.0);
    }

    CALayer *layerMask = [CALayer layer];
    layerMask.frame = self.wineImage.bounds;
    layerMask.contents = (id)mask.CGImage;
    self.wineImage.layer.mask = layerMask;
}

我之所以需要这样做,是因为表中具有分组样式的单元格高度不一致。顶部和底部单元格比"中间"单元格高1磅,而表中的单个单元格高2磅。对所有单元格中的图像使用相同的间距约束会导致图像部分地模糊某些单元格的单元格边框,或者在图像和其他单元格的边框之间保留空白。

如果有人能想出一个更简单的方法来攻击这个,我会感激的。

解决方案

根据下面标记的解决方案,删除图像间距约束,然后在图像和cell.contentview之间创建新的约束。我删除了代码来调整-(void)layoutSubviews方法的约束。我添加了代码来删除并对uiTableViewCell子类的awakeFromNib进行新的约束:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
- (void)awakeFromNib
{
    [super awakeFromNib];

    // Since Xcode 4.6.3 creates constrain relationships between the image and the cell, we need to delete and then recreate between the image and the cell.contentView

    [self removeConstraint:self.imageSpacingTopConstraint];
    [self removeConstraint:self.imageSpacingBottomConstraint];

    self.imageSpacingTopConstraint = [NSLayoutConstraint constraintWithItem:self.wineImage attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeTop multiplier:1.0 constant:0.0];
    self.imageSpacingBottomConstraint = [NSLayoutConstraint constraintWithItem:self.wineImage attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0.0];

    [self addConstraint:self.imageSpacingTopConstraint];
    [self addConstraint:self.imageSpacingBottomConstraint];
}


一个问题是,您正在更新layoutSubviews中的约束,但layoutSubviews在自动布局之后运行。您应该更新updateConstraints中的约束。

另一个问题是Xcode(至少通过4.6.3版)有问题。您的图像视图是单元格的contentView的子视图,并且约束应该在图像视图和contentView之间。但是在NIB和故事板中,Xcode错误地设置了图像视图和单元之间的约束。(注意:这个问题在Xcode5中已经解决了,所以如果你正在阅读这个,那么你可能不需要担心它,除非你是一个时间旅行者。)

如果在调试器中浏览视图层次结构,您会发现单元格的高度不同,但其内容视图的高度都相同。以下是默认大小:

1
2
3
4
5
6
7
8
9
10
Section Size  Row Position  Cell Height   contentView Height

     1            sole          46              43

     2            first         45              43
     2           second         45              43

     3+           first         45              43
     3+          middle         44              43
     3+           last          45              43

因此,当您依赖NIB/故事板中的约束来定位单元格的子视图时,最终会出现问题。

最简单的解决方案是编写代码(在单元格的awakeFromNib中),从nib/storyboard中删除约束,并在contentView和图像视图(以及contentView的任何其他子视图)之间创建新约束,这样就不需要根据单元格的位置修改约束常量。在它的部分。


您的代码中没有条件。因此,所有单元格都会更改。

现在您已经添加了代码,下面有两个可能的原因:

  • 如果topcell不是nil,if语句将永远不会生成0常量。这似乎不完全合乎逻辑。

  • if语句下面的layer部分可能再次更改预期的布局。