When in the view lifecycle does UITableViewCell create its outlets/labels/subviews?
Generally speaking, objects should create their properties in their designated initializer, unless there is an overriding design principle (or a performance/resource issue) which mandates that they create them later.
The designated initializer for UIView
(and NSView
on OS X) is -initWithFrame:
. The designated initializer for UITableView
is initWithFrame:style:
. Since a view will usually need to have it's visible subviews available immediately upon being added to its superview, it is fine to create and set them in the designated initializer.
-layoutSubviews
is intended for updating the layout, which is to say the center, bounds (or frame) and (optionally) transform. Now, because of the ordering of messages. You don't want to create your subviews in -layoutSubviews
because that method gets invoked repeatedly during the lifetime of your view, as its parent view's bounds changed and as it gets removed or re-added to its parent view, or as its subviews change.
In the case of UITableView, -layoutSubviews
is called every time the table is reloaded.
A typical exception to this rule is the creation of UITableViewCell
s used as rows of the table, which must be created dynamically.
The -heightForRowAtIndexPath
method provides a table view with the amount of space it needs to leave for that row's cell, but doesn't actually cause the cell to be resized. YOu have to set the cell's bounds yourself when creating the cell (or the cell can set its own bounds in -initWithStyle:reuseIdentifier:
, if it's designed to be a fixed value). IF your cell's size does not match the table's expectations, you will get gaps or overlaps.
For autoresizing masks to work properly, you must configure the view's initial frame yourself (either in code or in a nib). Autoresizing a view affects how it responds to changes in its parent view's bounds, but does not help in determining the view's initial frame.
Specifically, you must set the initial frames for subviews of your cells (and also ensure sibling subview ordering, etc). This is easier to do in nibs than in code.
Awais Hussain
Updated on June 09, 2022Comments
-
Awais Hussain almost 2 years
I am trying to create a
UIView
as a subview of a subclassedUITableViewCell
. Essentially I want a view which is the same size as the cell, and sits between the cell'scontentView
andbackgroundView
.I imagine that somewhere under the hood (possibly in
layoutSubviews
), there is a line inUITableViewCell.m
something like:if (self.contentView != nil) { [self addSubview:self.contentView]; }
If I want to mimic the way Apple does it, where should I put this code in my own custom
UITableViewCell
subclass?Also, in my first attempted implementation, the subview is displayed but it has the default cell height of 44px rather than the height I specified in
tableView:heightForRowAtIndexPath:
. There are also other small bugs that show up, which is why I'd like to try and replicate Apple's implementation rather than try my own semi-functional one.EDIT: Here's my code so far:
In
CustomTableViewCell.h
interface CustomTableViewCell : UITableViewCell @property (nonatomic, strong) UIView *newSubview; @end
In
CustomTableViewCell.m
- (void)layoutSubviews { [super layoutSubviews]; if (self.newSubview != nil) { self.newSubview.autoresizingMask = UIViewAutoresizingFlexibleHeight; [self insertSubview:self.newSubview aboveSubview:self.backgroundView]; } }
In
tableViewController.m
static NSString *CellIdentifier = @"Cell"; myCustomTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if (cell == nil) { cell = [[CustomTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]; } UIView *view = [[UIView alloc] initWithFrame:cell.frame]; view.backgroundColor = [UIColor orangeColor]; cell.newSubview = view;