使用 Autolayout 自定义具有动态高度和全宽图像的 TableViewCell
Posted
技术标签:
【中文标题】使用 Autolayout 自定义具有动态高度和全宽图像的 TableViewCell【英文标题】:Custom TableViewCell with dynamic height and full width image using Autolayout 【发布时间】:2015-07-28 16:40:15 【问题描述】:我真的被自动布局和自定义 tableviewcell 卡住了。
我希望我的 tableviewcell 具有动态高度。表格单元格应包含与表格视图单元格宽度相同的图像,高度应根据纵横比 0.6 进行调整
This is what it should look like
But this is what I get
为了让您清楚地了解发生了什么,我为 tableViewCell 及其子视图提供了一些漂亮的背景颜色……
绿色 = 缩略图视图 蓝色 = 自我 红色 = 内容视图 紫色 = 热点名称标签 黄色 = 类别标签这是我的代码的样子:
初始化器:
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self)
self.contentView.backgroundColor = [UIColor redColor];
self.backgroundColor = [UIColor blueColor];
CGFloat imageAspectRatio = 720/432;
CGFloat imageHeight = self.contentView.bounds.size.width / imageAspectRatio;
CGRect imageFrame = CGRectMake(0, 0, self.contentView.bounds.size.width,imageHeight);
self.thumbnailView = [[UIImageView alloc] initWithFrame:imageFrame];
[self.thumbnailView setBackgroundColor:[UIColor greenColor]];
[self.thumbnailView setContentMode:UIViewContentModeScaleAspectFill];
[self.thumbnailView.layer setMasksToBounds:true];
[self.contentView addSubview:self.thumbnailView];
self.hotspotNameLabel = [[UILabel alloc] initWithFrame:CGRectMake(40, 15, self.contentView.bounds.size.width - 80, 20)];
[self.hotspotNameLabel setAutoresizingMask:UIViewAutoresizingFlexibleWidth];
[self.hotspotNameLabel setTextColor:[UIColor colorWithWhite:(32/255.0) alpha:1]];
[self.hotspotNameLabel setLineBreakMode:NSLineBreakByWordWrapping];
[self.hotspotNameLabel setNumberOfLines:0]; // Unlimited Lines
[self.hotspotNameLabel setBackgroundColor:[UIColor purpleColor]];
[self.hotspotNameLabel setFont:[UIFont fontWithName:@"AvenirNext-Medium" size:20]];
[self.contentView addSubview:self.hotspotNameLabel];
// Category Label
self.categoryLabel = [[CategoryLabel alloc] initWithFrame:CGRectMake(40, 15, self.contentView.bounds.size.width - 80, 10)
categoryId:22 categoryName:@"Food"];
[self.contentView addSubview:self.categoryLabel];
// Constraints
[self.contentView setTranslatesAutoresizingMaskIntoConstraints:false];
[self.hotspotNameLabel setTranslatesAutoresizingMaskIntoConstraints:false]; // Enables autosizing
[self.categoryLabel setTranslatesAutoresizingMaskIntoConstraints:false];
[self.thumbnailView setTranslatesAutoresizingMaskIntoConstraints:false];
[self.contentView addConstraint:[NSLayoutConstraint constraintWithItem:self.thumbnailView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem: self.contentView attribute:NSLayoutAttributeWidth multiplier:1.0f constant:0]];
[self.contentView addConstraint:[NSLayoutConstraint constraintWithItem:self.thumbnailView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem: self.contentView attribute:NSLayoutAttributeWidth multiplier:0.6f constant:0]];
[self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[nameLabel]-0-|" options:0 metrics:nil views:@@"nameLabel": self.hotspotNameLabel]];
[self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-0-[thumbnail]-20-[nameLabel]-10-[categoryLabel]-0-|" options:0 metrics:nil views:@@"thumbnail": self.thumbnailView,@"nameLabel": self.hotspotNameLabel, @"categoryLabel":self.categoryLabel]];
return self;
布局子视图:
-(void)layoutSubviews
[super layoutSubviews];
[self.contentView setNeedsLayout];
[self.contentView layoutIfNeeded];
self.hotspotNameLabel.preferredMaxLayoutWidth = CGRectGetWidth(self.hotspotNameLabel.bounds);
tableView:HeightForRowAtIndexPath:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
return [self heightForLargeCellAtIndexPath:indexPath];
- (CGFloat)heightForLargeCellAtIndexPath:(NSIndexPath *)indexPath
LargeHotspotCell *sizingCell = [[LargeHotspotCell alloc] init];
[self configureLargeCell:sizingCell atIndexPath:indexPath];
[sizingCell setNeedsLayout];
[sizingCell layoutIfNeeded];
CGFloat height = [sizingCell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;
return height + 1 ;
【问题讨论】:
是否需要通过代码添加约束?在情节提要中做起来要容易得多 @NeilGaliaskarov 我也试过了,但我也无法用故事板完成它:s 我可以在这里发布一些带有基本概念的示例项目。你能提供你的 heightForRowAtIndexPath 方法实现吗 @NeilGaliaskarov 我将它添加到我的问题中:-) 请检查我的答案,如果它解决了您的问题,请不要忘记将其标记为已接受。 【参考方案1】:这是我解释自动布局基本概念的小教程。
您的第一步,应该是子类化UITableviewCell
,我将我的新单元命名为DynamicTableViewCell
并在身份检查器中分配它。
我将 UILabel 和 UIImageView 拖放到 contentView 中。 在带有 UILabel 约束的屏幕截图下方,我同时添加了前导和尾随空格约束,以使我的标签等于 contentView 宽度。它与单元格的底部对齐。
现在,是时候为 UIImageView 分配约束了。我正在添加纵横比 0.6 (imageHeight/imageWidth = 0.6) 并向 contentView 添加前导和尾随空格。随意使用常量来实现您想要的目的。
iphone5、iphone6模拟器中的最终结果
您的图像高度(绿色)在 5s 屏幕中为 60pt,在 6 屏幕中为 70pt,并且宽度调整正确:
为了您更好的理解,我发布Working Sample Project on github
【讨论】:
根据您对 iPhone5 与 iPhone6 的屏幕截图,我可以看到图像已正确缩放,但 tableviewcells 的高度没有改变。下面的标签可以有多行(因此这也应该影响单元格的高度)并且应该与图像的底部对齐。我认为您的标签现在显示在图像上方。 :-/ 我使所有单元格的单元格高度相等,您可以进一步自定义。 是的,但我已经能够做到这一点,但是我无法让文本显示在图像下方……我想将标签放置在图像下方的那一刻:[self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-0-[thumbnail]-[nameLabel]-[categoryLabel]-10-|" options:0 metrics:nil views:@@"thumbnail": self.thumbnailView,@"nameLabel": self.hotspotNameLabel,@"categoryLabel": self.categoryLabel]];
then它看起来不错,但我收到以下错误(请参阅下一条评论)
015-07-29 09:19:41.992 appName[6760:1818580] 无法同时满足约束。可能以下列表中的至少一个约束是您不想要的......以上是关于使用 Autolayout 自定义具有动态高度和全宽图像的 TableViewCell的主要内容,如果未能解决你的问题,请参考以下文章
AutoLayout 在地图标注中动态调整 UILabel 高度和宽度?
Autolayout - 当一个视图具有动态高度时,在 UITableViewCell 中垂直居中两个视图
iOS UITableView+FDTemplateLayoutCell 配合AutoLayout分分钟教你实现动态高度自适应
使用 Auto Layout 创建具有多个不同自定义单元格的 UITableView 具有几乎相同的子视图