1.前言
2.问题发现
3.解决问题
4.列举下解决问题的方法
1.设置 label的 preferredMaxLayoutWidth
- (CGRect)boundingRectWithSize:(CGSize)size options:(NSStringDrawingOptions)options attributes:(nullable NSDictionary<NSString *, id> *)attributes context:(nullable NSStringDrawingContext *)context NS_AVAILABLE(10_11, 7_0)
就像这个方法中size size的宽就是要设置label能够显示的宽,如果给的不对当然计算出的高度也会不对,如果给的小了计算的高度就高,给的大了计算的高度就低
- 加 [cell layoutIfNeeded]
- (CGFloat)fd_heightForCellWithIdentifier:(NSString *)identifier configuration:(void (^)(id))configuration
{
if (!identifier) {
return 0;
}
// Fetch a cached template cell for `identifier`.
UITableViewCell *cell = [self fd_templateCellForReuseIdentifier:identifier];
// Manually calls to ensure consistent behavior with actual cells (that are displayed on screen).
[cell prepareForReuse];
// Customize and provide content for our template cell.
if (configuration) {
configuration(cell);
}
CGFloat contentViewWidth = CGRectGetWidth(self.frame);
// If a cell has accessory view or system accessory type, its content view's width is smaller
// than cell's by some fixed values.
if (cell.accessoryView) {
contentViewWidth -= 16 + CGRectGetWidth(cell.accessoryView.frame);
} else {
static CGFloat systemAccessoryWidths[] = {
[UITableViewCellAccessoryNone] = 0,
[UITableViewCellAccessoryDisclosureIndicator] = 34,
[UITableViewCellAccessoryDetailDisclosureButton] = 68,
[UITableViewCellAccessoryCheckmark] = 40,
[UITableViewCellAccessoryDetailButton] = 48
};
contentViewWidth -= systemAccessoryWidths[cell.accessoryType];
}
CGSize fittingSize = CGSizeZero;
// If auto layout enabled, cell's contentView must have some constraints.
BOOL autoLayoutEnabled = cell.contentView.constraints.count > 0 && !cell.fd_enforceFrameLayout;
if (autoLayoutEnabled) {
// Add a hard width constraint to make dynamic content views (like labels) expand vertically instead
// of growing horizontally, in a flow-layout manner.
if (IOS_VERSION > 10.2) {
[cell layoutIfNeeded];
}
NSLayoutConstraint *tempWidthConstraint =
[NSLayoutConstraint constraintWithItem:cell.contentView
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:contentViewWidth];
[cell.contentView addConstraint:tempWidthConstraint];
// Auto layout engine does its math
fittingSize = [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];
[cell.contentView removeConstraint:tempWidthConstraint];
} else {
// If not using auto layout, you have to override "-sizeThatFits:" to provide a fitting size by yourself.
// This is the same method used in iOS8 self-sizing cell's implementation.
// Note: fitting height should not include separator view.
SEL selector = @selector(sizeThatFits:);
BOOL inherited = ![cell isMemberOfClass:UITableViewCell.class];
BOOL overrided = [cell.class instanceMethodForSelector:selector] != [UITableViewCell instanceMethodForSelector:selector];
if (inherited && !overrided) {
NSAssert(NO, @"Customized cell must override '-sizeThatFits:' method if not using auto layout.");
}
fittingSize = [cell sizeThatFits:CGSizeMake(contentViewWidth, 0)];
}
// Add 1px extra space for separator line if needed, simulating default UITableViewCell.
if (self.separatorStyle != UITableViewCellSeparatorStyleNone) {
fittingSize.height += 1.0 / [UIScreen mainScreen].scale;
}
if (autoLayoutEnabled) {
[self fd_debugLog:[NSString stringWithFormat:@"calculate using auto layout - %@", @(fittingSize.height)]];
} else {
[self fd_debugLog:[NSString stringWithFormat:@"calculate using frame layout - %@", @(fittingSize.height)]];
}
return fittingSize.height;
}
*重点在这里
1.png
3.给cell.contentView 加左右约束
2.png
<strong>什么,你还懒得敲,要我发源码!好吧忍不了你了<strong>
- (CGFloat)fd_heightForCellWithIdentifier:(NSString *)identifier configuration:(void (^)(id))configuration
{
if (!identifier) {
return 0;
}
// Fetch a cached template cell for `identifier`.
UITableViewCell *cell = [self fd_templateCellForReuseIdentifier:identifier];
// Manually calls to ensure consistent behavior with actual cells (that are displayed on screen).
[cell prepareForReuse];
// Customize and provide content for our template cell.
if (configuration) {
configuration(cell);
}
CGFloat contentViewWidth = CGRectGetWidth(self.frame);
// If a cell has accessory view or system accessory type, its content view's width is smaller
// than cell's by some fixed values.
if (cell.accessoryView) {
contentViewWidth -= 16 + CGRectGetWidth(cell.accessoryView.frame);
} else {
static CGFloat systemAccessoryWidths[] = {
[UITableViewCellAccessoryNone] = 0,
[UITableViewCellAccessoryDisclosureIndicator] = 34,
[UITableViewCellAccessoryDetailDisclosureButton] = 68,
[UITableViewCellAccessoryCheckmark] = 40,
[UITableViewCellAccessoryDetailButton] = 48
};
contentViewWidth -= systemAccessoryWidths[cell.accessoryType];
}
CGSize fittingSize = CGSizeZero;
// If auto layout enabled, cell's contentView must have some constraints.
BOOL autoLayoutEnabled = cell.contentView.constraints.count > 0 && !cell.fd_enforceFrameLayout;
if (autoLayoutEnabled) {
// Add a hard width constraint to make dynamic content views (like labels) expand vertically instead
// of growing horizontally, in a flow-layout manner.
if (IOS_VERSION > 10.2) {
[cell.contentView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(0).priorityLow();
make.right.mas_equalTo(0).priorityLow();
}];
}
NSLayoutConstraint *tempWidthConstraint =
[NSLayoutConstraint constraintWithItem:cell.contentView
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:contentViewWidth];
[cell.contentView addConstraint:tempWidthConstraint];
// Auto layout engine does its math
fittingSize = [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];
[cell.contentView removeConstraint:tempWidthConstraint];
} else {
// If not using auto layout, you have to override "-sizeThatFits:" to provide a fitting size by yourself.
// This is the same method used in iOS8 self-sizing cell's implementation.
// Note: fitting height should not include separator view.
SEL selector = @selector(sizeThatFits:);
BOOL inherited = ![cell isMemberOfClass:UITableViewCell.class];
BOOL overrided = [cell.class instanceMethodForSelector:selector] != [UITableViewCell instanceMethodForSelector:selector];
if (inherited && !overrided) {
NSAssert(NO, @"Customized cell must override '-sizeThatFits:' method if not using auto layout.");
}
fittingSize = [cell sizeThatFits:CGSizeMake(contentViewWidth, 0)];
}
// Add 1px extra space for separator line if needed, simulating default UITableViewCell.
if (self.separatorStyle != UITableViewCellSeparatorStyleNone) {
fittingSize.height += 1.0 / [UIScreen mainScreen].scale;
}
if (autoLayoutEnabled) {
[self fd_debugLog:[NSString stringWithFormat:@"calculate using auto layout - %@", @(fittingSize.height)]];
} else {
[self fd_debugLog:[NSString stringWithFormat:@"calculate using frame layout - %@", @(fittingSize.height)]];
}
return fittingSize.height;
}
如果你的是其他版本的 自己对比找下,如果你是最新版的看下图
22.png方法
33.png
位置
44.png
网友评论
另,GitHub上的代码我用cocoapod安装1.6,结果拉取的代码没有变,在github上手动下载的代码是OK的,你是没有发布吗?(用cocoapod管理的1.6不对)
当你的XXXCell.xib文件是基于iPhone7 Simulator尺寸布局的,运行于iPhone7 Plus Simulator模拟器就会出现上下留白,系统是以iPhone7 Simulator宽度作为换行的宽度,到了iPhone7 Plus Simulator,自然上下留空白了。希望能解决这个问题,iOS10.3之前没有这个问题。
if (IOS_VERSION > 10.2) {
[cell.contentView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(0).priorityLow();
make.right.mas_equalTo(0).priorityLow();
}];
}
在7P上运行还有约束冲突,
"<NSLayoutConstraint:0x6080000990f0 UITableViewCellContentView:0x7fb604f0d500.width == 414>",
"<NSLayoutConstraint:0x600000097430 UITableViewCellContentView:0x7fb604f0d500.width == 320>"
如果把cell的XIB的宽度手动拉到414,那么5S、7、7P显示都正常,但是还是会有约束冲突
我的一个例子你看下(分别在iOS的5S、7、7P下测试),https://github.com/yansun2006/TestLayoutCellBugProj