如何在表视图中的UITableViewCells中使用“自动布局”,让每个单元格的内容和子视图确定行高度(自身/自动),同时保持平滑的滚动性能?
当前回答
我刚刚遇到一个非常重要的问题,作为回答发布。
@smileyborg的回答基本正确。但是,如果自定义单元格类的layoutSubviews方法中有任何代码,例如设置preferredMaxLayoutWidth,则不会使用以下代码运行:
[cell.contentView setNeedsLayout];
[cell.contentView layoutIfNeeded];
这让我困惑了一阵子。然后我意识到这是因为它们只触发contentView上的layoutSubview,而不是单元格本身。
我的工作代码如下:
TCAnswerDetailAppSummaryCell *cell = [self.tableView dequeueReusableCellWithIdentifier:@"TCAnswerDetailAppSummaryCell"];
[cell configureWithThirdPartyObject:self.app];
[cell layoutIfNeeded];
CGFloat height = [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;
return height;
注意,如果您正在创建一个新的单元格,我很确定您不需要调用setNeedsLayout,因为它应该已经设置好了。在保存对单元格的引用的情况下,您可能应该调用它。不管怎样,它都不会造成任何影响。
另一个提示是,如果您使用的是单元格子类,则需要设置preferredMaxLayoutWidth等属性。正如@smileyborg提到的,“您的表视图单元格的宽度尚未固定到表视图的宽度”。这是正确的,如果您在子类中而不是在视图控制器中进行工作,则会遇到麻烦。但是,此时可以使用表格宽度简单地设置单元格框架:
例如,在计算高度时:
self.summaryCell = [self.tableView dequeueReusableCellWithIdentifier:@"TCAnswerDetailDefaultSummaryCell"];
CGRect oldFrame = self.summaryCell.frame;
self.summaryCell.frame = CGRectMake(oldFrame.origin.x, oldFrame.origin.y, self.tableView.frame.size.width, oldFrame.size.height);
(我碰巧缓存了这个特定的单元以供重用,但这无关紧要)。
其他回答
假设您有一个带有子视图的单元格,并且希望该单元格的高度足够高,以包含子视图+填充。
1) 将子视图的底部约束设置为cell.contentView减去所需的填充。不要对单元格或cell.contentView本身设置约束。
2) 将tableView的rowHeight属性或tableView:heightForRowAtIndexPath:设置为UITableViewAutomaticDimension。
3) 将tableView的estimatedRowHeight属性或tableView:estimatedHeightForRowAtIndexPath:设置为高度的最佳猜测。
就是这样。
swift 4
@IBOutlet weak var tableViewHeightConstraint: NSLayoutConstraint!
@IBOutlet weak var tableView: UITableView!
private var context = 1
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.addObserver(self, forKeyPath: "contentSize", options: [.new,.prior], context: &context)
}
// Added observer to adjust tableview height based on the content
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if context == &self.context{
if let size = change?[NSKeyValueChangeKey.newKey] as? CGSize{
print("-----")
print(size.height)
tableViewHeightConstraint.constant = size.height + 50
}
}
}
//Remove observer
deinit {
NotificationCenter.default.removeObserver(self)
}
我必须使用动态视图(通过代码设置视图和约束),当我想设置preferredMaxLayoutWidth标签的宽度为0时。所以我有错误的细胞高度。
然后我添加了
[cell layoutSubviews];
执行之前
[cell setNeedsUpdateConstraints];
[cell updateConstraintsIfNeeded];
之后,标签的宽度符合预期,动态高度计算正确。
关于@smileyborg接受的答案,我发现
[cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize]
在某些约束不明确的情况下是不可靠的。最好使用下面UIView上的帮助器类别强制布局引擎计算一个方向上的高度:
-(CGFloat)systemLayoutHeightForWidth:(CGFloat)w{
[self setNeedsLayout];
[self layoutIfNeeded];
CGSize size = [self systemLayoutSizeFittingSize:CGSizeMake(w, 1) withHorizontalFittingPriority:UILayoutPriorityRequired verticalFittingPriority:UILayoutPriorityFittingSizeLevel];
CGFloat h = size.height;
return h;
}
其中w:是表视图的宽度
动态表视图单元格高度和自动布局
解决故事板自动布局问题的好方法:
- (CGFloat)heightForImageCellAtIndexPath:(NSIndexPath *)indexPath {
static RWImageCell *sizingCell = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sizingCell = [self.tableView dequeueReusableCellWithIdentifier:RWImageCellIdentifier];
});
[sizingCell setNeedsLayout];
[sizingCell layoutIfNeeded];
CGSize size = [sizingCell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];
return size.height;
}
推荐文章
- 如何使用Xcode创建。ipa文件?
- 动态改变UILabel的字体大小
- 在iPhone上确定用户是否启用了推送通知
- 是否有可能禁用浮动头在UITableView与UITableViewStylePlain?
- 错误ITMS-9000:“冗余二进制文件上传。火车1.0版本已经有一个二进制版本上传。
- Swift -转换为绝对值
- 从父iOS访问容器视图控制器
- 自定义dealloc和ARC (Objective-C)
- 调整UITableView的大小以适应内容
- 在代码中为UIButton设置一个图像
- NSRange从Swift Range?
- UICollectionView中的单元格间距
- 我如何在我的iOS应用程序中每n分钟得到一个后台位置更新?
- 如何使用iOS创建GUID/UUID
- 禁用所呈现视图控制器的交互式撤销