Auto layout constraints issue on iOS7 in UITableViewCell
Solution 1:
I had this problem as well.. It appears that the contentView's frame doesn't get updated until layoutSubviews
is called however the frame of the cell is updated earlier leaving the contentView's frame set to {0, 0, 320, 44}
at the time when the constraints are evaluated.
After looking at the contentView in more detail, It appears that autoresizingMasks are no longer being set.
Setting the autoresizingMask before you constrain your views can resolve this issue:
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:UITableViewCellStyleDefault reuseIdentifier:reuseIdentifier];
if (self)
{
self.contentView.autoresizingMask = UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleWidth;
[self loadViews];
[self constrainViews];
}
return self;
}
Swift5, ios14:
contentView.autoresizingMask = [.flexibleHeight, .flexibleWidth]
Solution 2:
Apparently there is something wrong with UITableViewCell and UICollectionViewCell on iOS 7 using iOS 8 SDK.
You can update cell's contentView when the cell is reused like this:
For Static UITableViewController:
#ifdef __IPHONE_OS_VERSION_MIN_REQUIRED
#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_8_0
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [super tableView:tableView cellForRowAtIndexPath:indexPath];
if (NSFoundationVersionNumber <= NSFoundationVersionNumber_iOS_7_1)
{
cell.contentView.frame = cell.bounds;
cell.contentView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleRightMargin |UIViewAutoresizingFlexibleTopMargin |UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleBottomMargin;
}
//your code goes here
return cell;
}
#endif
#endif
Since Static Table View Controllers are fragile and can easy be broken if you implement some datasource or deletegate methods - there are checks that will ensure that this code will only be compiled and run on iOS 7
It is similar for standard dynamic UITableViewController:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellID = @"CellID";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];
if (NSFoundationVersionNumber <= NSFoundationVersionNumber_iOS_7_1)
{
cell.contentView.frame = cell.bounds;
cell.contentView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleRightMargin |UIViewAutoresizingFlexibleTopMargin |UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleBottomMargin;
}
//your code goes here
return cell;
}
For this case we don't need the compilation extra check, since implementing this method is required.
The idea is the same for both cases and for UICollectionViewCell, like commented in this thread: Autoresizing issue of UICollectionViewCell contentView's frame in Storyboard prototype cell (Xcode 6, iOS 8 SDK) happens when running on iOS 7 only
Solution 3:
As cells are being reused and the height can change based on the content, I think in general it would be better to set the priority of spacings to less than required.
In your case the UIImageView has a spacing of 15 to the top and the bottom view has a spacing of 0 to the bottom. If you set the priority of those constraints to 999 (instead of 1000), the app will not crash, because the constraints are not required.
Once the layoutSubviews method is called, the cell will have the correct height, and the constraints can be satisfied normally.
Solution 4:
I still didn't find a good solution for storyboards... Some info also here: https://github.com/Alex311/TableCellWithAutoLayout/commit/bde387b27e33605eeac3465475d2f2ff9775f163#commitcomment-4633188
From what they advice there:
self.contentView.bounds = CGRectMake(0, 0, 99999, 99999);
I've induced my solution:
- right click the storyboard
- Open As -> Source Code
- search for string "44" there
- it's gonna be like
.
<tableView hidden="YES" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="none" allowsSelection="NO" rowHeight="44" ...
<tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="ChatMessageCell" id="bCG-aU-ivE" customClass="ChatMessageCell">
<rect key="frame" x="0.0" y="22" width="320" height="44"/>
.
- replace rowHeight="44" with rowHeight="9999" and height="44" with height="9999"
- right click the storyboard
- Open As -> Interface Builder
- run your app and check the output