Reputation: 239
I'm trying to pin a subview inside of a custom UITableViewCell
class to the left side of the cell's contentView
. I'm adding the subview to the contentView
inside of the initWithStyle
method of the subclass, as well as adding constraints inside of that method. Unfortunately, I have two problems:
The subview is not pinning to the left edge of the contentView
even though I'm using the following code to do so:
[self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"|[_animatedView]-[_aTextField][_rightImageView]|"
options:NSLayoutFormatDirectionLeftToRight
metrics:nil views:viewDictionary]];
To me, that format string should be pinning the _animatedView
to the left side of the contentView
, and then appending the other subsequent views as close as possible afterwards. Instead, all three views show up together in the proper order in the middle of the contentView
, instead of at the left edge. I'm new to using autolayout, so this might be a confusion of how the format strings work on my part.
Solved: Thanks to Guillaume's suggestion, I was able to do a little bit of testing and find out that the reason that the cell contents were wildly displaced as I scrolled through the table was that I had not overridden the UITableViewCell
method, prepareForReuse
. This method is called when a UITableViewCell
is prepared to be reused to display information for another object in the UITableView
, which incidentally happens when scrolling occurs. The solution was as simple as inserting the following code into my UITableViewCell
subclass:
-(void) prepareForReuse
{
[self setNeedsUpdateConstraints];
}
The other problem is that the constraints appear to not be enforced until I select a row of the TableView where the custom cells are being used. Is there a place other than initWithStyle
I should be setting up the constraints or is this a different issue?
Update:
CustomTableCell.m
@interface ListTableCell ()
{
NSDictionary *_viewsForConstraints; // Used inside updateConstraints method.
NSArray *_animatedViewSizeConstraints;
NSArray *_centeringConstraints;
NSArray *_horizontalConstraints;
}
@end
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self)
{
// Set up the cell elements.
self.contentView.translatesAutoresizingMaskIntoConstraints = NO;
self.animatedView = [[AnimatedView alloc] initWithFrame:CGRectZero];
self.animatedView.translatesAutoresizingMaskIntoConstraints = NO;
[self.contentView addSubview:self.animatedView];
self.aTextField = [[UITextField alloc] initWithFrame:CGRectZero];
self.aTextField.textColor = [UIColor whiteColor];
self.aTextField.translatesAutoresizingMaskIntoConstraints = NO;
[self.contentView addSubview:self.aTextField];
self.rightImageView = [[UIImageView alloc] initWithFrame:CGRectZero];
self.rightImageView.translatesAutoresizingMaskIntoConstraints = NO;
[self.contentView addSubview:self.rightImageView];
_viewForConstraints = NSDictionaryOfVariableBindings(_animatedView,
_aTextField, _rightImageView);
// Add height/width constraints to the animated view.
NSLayoutConstraint *heightConstraint =
[NSLayoutConstraint constraintWithItem:self.animatedView attribute:NSLayoutAttributeHeight relatedBy:0 toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:self.contentView.frame.size.height];
NSLayoutConstraint *aspectRatioConstraint = [NSLayoutConstraint constraintWithItem:self.animatedView attribute:NSLayoutAttributeHeight relatedBy:0 toItem:self.animatedview attribute:NSLayoutAttributeWidth multiplier:1.0 constant:0];
_animatedViewSizeConstraints = @[heightConstraint, aspectRatioConstraint];
// Center elements vertically.
NSLayoutConstraint *animatedViewVerticalCenterConstraint =
[NSLayoutConstraint constraintWithItem:self.animatedView
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:self.contentView
attribute:NSLayoutAttributeCenterY
multiplier:1.0
constant:0.0];
NSLayoutConstraint *aTextFieldVerticalCenterConstraint =
[NSLayoutConstraint constraintWithItem:self.aTextField
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:self.contentView
attribute:NSLayoutAttributeCenterY
multiplier:1.0
constant:0.0];
NSLayoutConstraint *rightImageVerticalCenterConstraint =
[NSLayoutConstraint constraintWithItem:self.rightImageView
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:self.contentView
attribute:NSLayoutAttributeCenterY
multiplier:1.0
constant:0.0];
_centeringConstraints = @[animatedViewVerticalCenterConstraint,
aTextFieldVerticalCenterConstraint, rightImageVerticalCenterConstraint];
_horizontalConstraints = [NSLayoutConstraint constraintsWithVisualFormat:@"|[_animatedView]-[_aTextField][_rightImageView]|"
options:NSLayoutFormatDirectionLeftToRight metrics:nil views:viewDictionary]];
self.backgroundColor = [UIColor greenColor];
self.editingAccessoryType = UITableViewCellAccessoryNone;
self.accessoryType = UITableViewCellAccessoryNone;
self.selectionStyle = UITableViewCellSelectionStyleNone;
self.aTextField.userInteractionEnabled = NO;
[self setNeedsUpdateConstraints];
}
-(void) updateConstraints
{
[super updateConstraints];
[self.contentView addConstraints:_animatedViewSizeConstraints];
[self.contentView addConstraints:_centeringConstraints];
[self.contentView addConstraints:_horizontalConstraints];
}
TableViewController.m
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"Cell";
CustomTableCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
// Configure the cell.
cell.aTextField.text = @"Test Text";
cell.aTextField.delegate = self;
return cell;
}
I can confirm that initWithStyle
is getting called because the background is always green and subviews always show up, they just show up very oddly spaced initially.
Thank you for any help with this!
Upvotes: 3
Views: 3389
Reputation: 12504
Don't turn off translatesAutoresizingMaskIntoConstraints
of the contentView
of your tableview.
I've run into this problem before.
Remove this line: self.contentView.translatesAutoresizingMaskIntoConstraints = NO;
Essentially, your view is pinning to the left edge of the contentView
but the content view isn't the full width of the cell. You can use something like DCIntrospect-ARC
or Reveal to see that it's the case.
Upvotes: 0
Reputation: 11016
You should setup your constraints in the updateConstraints
method. From the doc:
Custom views that set up constraints themselves should do so by overriding this method.
That should at least solve your #2 issue.
Upvotes: 2