Reputation: 581
I have a UITableViewController, Grouped style, with a custom UITableViewCell. In the UITableViewCell I have NSLayoutConstraints, defined in a storyboard (on the prototype cell), that dictate the size and positioning of a UIImageView. These NSLayoutConstraints are linked to properties of the UITableViewCell subclass.
In the -(void)layoutSubviews method of the subclassed UITableViewCell, I'm attempting to use
self.topSpacingConstraint.constant = 0;
to change the arrangement on a per-cell basis.
That line of code adjusts the constraint for all of my cells, though. I don't understand why, and I don't know how to set the constraint for a single cell.
Update
Here's the full code for the -(void)layoutSubviews
method of the UITableViewCell subclass. self.topCell
and self.bottomCell
are properties set by the UITableViewController while configuring the cell. Based on those values, I'm trying to update the AutoLayout spacing of an image on a per-cell basis:
- (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;
}
My need to do this stems from the inconsistent height of cells on the table with Grouped style. The top and bottom cell are 1pt taller than 'middle' cells, while a single cell in the table is 2pts taller. Using the same spacing constraints for the image in all cells results in the image partially obscuring the cell borders for some cells, or leaving whitespace between the image and the border in others.
If anyone can think of an easier way to attack this, I'd appreciate it.
Solution
Per the marked solution below, removing the image spacing constraints and then creating new constraints between the image and the cell.contentView did the trick. I removed the code to adjust the constraints from the -(void)layoutSubviews
method. I added the code to remove and make new constraints to awakeFromNib
of the UITableViewCell subclass:
- (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];
}
Upvotes: 0
Views: 2692
Reputation: 385540
One problem is you're updating your constraints in layoutSubviews
, but layoutSubviews
runs after auto layout. You should update your constraints in updateConstraints
instead.
Another problem is Xcode, through at least version 4.6.3, is buggy. Your image view is a subview of the cell's contentView
, and constraints should be between the image view and the contentView
. But in nibs and storyboards, Xcode incorrectly sets the constraints between the image view and the cell. (Note: this problem was fixed in Xcode 5 so you probably don't need to worry about it if you are reading this unless you are a time traveler.)
If you poke around in your view hierarchy in the debugger, you'll discover that the cells have varying heights, but their content views all have the same height. Here are the default sizes:
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
Thus when you rely on constraints in your nib/storyboard to position your cell's subviews, you end up with problems.
The simplest solution is to just write code (in your cell's awakeFromNib
) that deletes the constraints from the nib/storyboard, and creates new constraints between the contentView
and the image view (and any other subviews of the contentView
.) This should eliminate the need to modify the constraint constants based on the cell's position within its section.
Upvotes: 2
Reputation: 80265
There is no conditionality in your code. Therefore all cells are changed.
Now that you have added the code, there are 2 possible reasons that come to mind:
The if statement will never produce a 0 constant if topCell is not nil
. That does not seem entirely logical.
The layer section below the if statement could potentially change the expected layout again.
Upvotes: 0