AutoLayout多行UILabel剪掉一些文字

我试图学习汽车的布局,最终以为我发现这件事情时就挂上了。 我在玩原型单元和标签。 我正在尝试一个

  • 标题, titleLbl – 图片中的蓝色框
  • 钱, moneyLbl – 图片中的绿色框
  • Subtitle / Description, subTitleLbl – 图片中的红色框

到目前为止,我有这样的:

iphone截图

我想要达到的是:

  • 绿框应该始终显示在1行上
  • 绿框内的值应该以蓝框为中心
  • 蓝色框将会占用剩余的空间(在2之间为水平约束-8px),并且如果需要的话在多行上显示
  • 红色框应该在下面,根据需要显示多行。

正如你所看到的,除了最后一行的例子之外,这几乎都是有效的。 我试图研究这个问题,从我能收集的内容来看,这与内在内容大小有关。 许多post在线推荐设置setPreferredMaxLayoutWidth ,我已经在多个地方为titleLbl做了这个,并没有任何效果。 只有将其硬编码为180时,才能得到结果,但是它还在文本上方/下方的其他蓝色框中添加了空白/填充,大大增加了红色/蓝色框之间的空间。

这是我的约束:

标题: 标题限制

钱: 金钱约束

字幕: 字幕限制

基于我用其他文本样本运行的testing,它似乎使用了故事板中显示的宽度,但是任何尝试更正它都不起作用。

我已经创build了一个单元格的伊娃,并用它来创build单元格的高度:

 - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { [sizingCellTitleSubMoney.titleLbl setText:[[tableViewData objectAtIndex:indexPath.row] objectForKey:@"title"]]; [sizingCellTitleSubMoney.subtitleLbl setText:[[tableViewData objectAtIndex:indexPath.row] objectForKey:@"subtitle"]]; [sizingCellTitleSubMoney.moneyLbl setText:[[tableViewData objectAtIndex:indexPath.row] objectForKey:@"cost"]]; [sizingCellTitleSubMoney layoutIfNeeded]; CGSize size = [sizingCellTitleSubMoney.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize]; return size.height+1; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { MATitleSubtitleMoneyTableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifierTitleSubTitleMoney]; if(!cell) { cell = [[MATitleSubtitleMoneyTableViewCell alloc] init]; } cell.titleLbl.layer.borderColor = [UIColor blueColor].CGColor; cell.titleLbl.layer.borderWidth = 1; cell.subtitleLbl.layer.borderColor = [UIColor redColor].CGColor; cell.subtitleLbl.layer.borderWidth = 1; cell.moneyLbl.layer.borderColor = [UIColor greenColor].CGColor; cell.moneyLbl.layer.borderWidth = 1; [cell.titleLbl setText:[[tableViewData objectAtIndex:indexPath.row] objectForKey:@"title"]]; [cell.subtitleLbl setText:[[tableViewData objectAtIndex:indexPath.row] objectForKey:@"subtitle"]]; [cell.moneyLbl setText:[[tableViewData objectAtIndex:indexPath.row] objectForKey:@"cost"]]; return cell; } 

我试过在单元的布局子视图中设置setPreferredMaxLayoutWidth

 - (void)layoutSubviews { [super layoutSubviews]; NSLog(@"Money lbl: %@", NSStringFromCGRect(self.moneyLbl.frame)); NSLog(@"prefferredMaxSize: %f \n\n", self.moneyLbl.frame.origin.x-8); [self.titleLbl setPreferredMaxLayoutWidth: self.moneyLbl.frame.origin.x-8]; } 

日志:

 2014-04-30 21:37:32.475 AutoLayoutTestBed[652:60b] Money lbl: {{209, 20}, {91, 61}} 2014-04-30 21:37:32.475 AutoLayoutTestBed[652:60b] prefferredMaxSize: 201.000000 

这是我所期望的,因为这两个元素之间有8px,控制台validation了这一点。 无论我将多less文本添加到蓝色框中(与故事板相同),它在第一行上都能完美地工作,但是对绿色框的任何增加都会抛出宽度计算。 我已经尝试在tableView:willDisplayCelltableView:heightForRowAtIndexPath:设置这个以及其他问题的答案。 但不pipe它是不是布局。

任何帮助,想法或意见将不胜感激

阅读后find更好的答案: http : //johnszumski.com/blog/auto-layout-for-table-view-cells-with-dynamic-heights

创build一个UILabel子类来覆盖layoutSubviews如下所示:

 - (void)layoutSubviews { [super layoutSubviews]; self.preferredMaxLayoutWidth = CGRectGetWidth(self.bounds); [super layoutSubviews]; } 

这确保preferredMaxLayoutWidth总是正确的。

更新:

经过多次发布的iOS和testing更多的用例我发现上述不足以满足每一个案件。 从iOS 8(我相信),在某些情况下,只有在屏幕加载之前调用didSet bounds

在iOS 9中最近我遇到了另一个问题,当使用带有UITableView的模态UIVIewController时, layoutSubviewsset bounds heightForRowAtIndexPath 之后被调用。 经过多次debugging,唯一的解决scheme是覆盖set frame

下面的代码现在似乎是必要的,以确保它适用于所有的iOS,控制器,屏幕尺寸等

 override public func layoutSubviews() { super.layoutSubviews() self.preferredMaxLayoutWidth = self.bounds.width super.layoutSubviews() } override public var bounds: CGRect { didSet { self.preferredMaxLayoutWidth = self.bounds.width } } override public var frame: CGRect { didSet { self.preferredMaxLayoutWidth = self.frame.width } } 

我不知道我是否理解你,我的解决scheme与最好的解决scheme相去甚远,但这里是:

我在被切割的标签上添加了一个高度限制,将限制连接到单元格的出口。 我已经覆盖了layoutSubview方法:

 - (void) layoutSubviews { [super layoutSubviews]; [self.badLabel setNeedsLayout]; [self.badLabel layoutIfNeeded]; self.badLabelHeightConstraint.constant = self.badLabel.intrinsicContentSize.height; } 

和中提琴! 请尝试该方法并告诉我结果,谢谢。

Omg,只是有同样的问题。 @Simon McLoughlin的回答对我没有帮助。 但

 titleLabel.adjustsFontSizeToFitWidth = true 

做了一个魔术! 它的作品,我不知道为什么,但它确实。 是的,您的标签也必须具有明确的preferredMaxLayoutWidth值。

我花了一些时间来包装细胞,看起来像这样:

 +--------------------------------------------------+ | This is my cell.contentView | | +------+ +-----------------+ +--------+ +------+ | | | | | multiline | | title2 | | | | | | img | +-----------------+ +--------+ | img | | | | | +-----------------+ +--------+ | | | | | | | title3 | | title4 | | | | | +------+ +-----------------+ +--------+ +------+ | | | +--------------------------------------------------+ 

经过多次尝试,我find了解决scheme,如何使用实际工作的原型单元。

主要的麻烦是我的标签可能会或可能不在那里。 每个元素都应该是可选的。

首先,我们的“原型”单元应该只在我们不处于“真实”环境时才进行布局。

因此,我创build了标志'heightCalculationInProgress'。

当有人(tableView的dataSource)要求计算高度时,我们正在使用block向原型单元格提供数据:然后我们要求我们的原型单元格布局内容并从中获取高度。 简单。

为了避免使用layoutSubviewrecursion的iOS7 bug,有一个“layoutingLock”variables

 - (CGFloat)heightWithSetupBlock:(nonnull void (^)(__kindof UITableViewCell *_Nonnull cell))block { block(self); self.heightCalculationInProgress = YES; [self setNeedsLayout]; [self layoutIfNeeded]; self.layoutingLock = NO; self.heightCalculationInProgress = NO; CGFloat calculatedHeight = [self.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height; CGFloat height = roundf(MAX(calculatedHeight, [[self class] defaultHeight])); return height; } 

外面的这个“块”可能是这样的:

 [prototypeCell heightWithSetupBlock:^(__kindof UITableViewCell * _Nonnull cell) { @strongify(self); cell.frame = CGRectMake(0, 0, CGRectGetWidth(self.view.frame), 0); cell.dataObject = dataObject; cell.multilineLabel.text = @"Long text"; // Include any data here }]; 

现在开始最有趣的部分。 布点:

 - (void)layoutSubviews { if(self.layoutingLock){ return; } // We don't want to do this layouting things in 'real' cells if (self.heightCalculationInProgress) { // Because of: // Support for constraint-based layout (auto layout) // If nonzero, this is used when determining -intrinsicContentSize for multiline labels // We're actually resetting internal constraints here. And then we could reuse this cell with new data to layout it correctly _multilineLabel.preferredMaxLayoutWidth = 0.f; _title2Label.preferredMaxLayoutWidth = 0.f; _title3Label.preferredMaxLayoutWidth = 0.f; _title4Label.preferredMaxLayoutWidth = 0.f; } [super layoutSubviews]; // We don't want to do this layouting things in 'real' cells if (self.heightCalculationInProgress) { // Make sure the contentView does a layout pass here so that its subviews have their frames set, which we // need to use to set the preferredMaxLayoutWidth below. [self.contentView setNeedsLayout]; [self.contentView layoutIfNeeded]; // Set the preferredMaxLayoutWidth of the mutli-line bodyLabel based on the evaluated width of the label's frame, // as this will allow the text to wrap correctly, and as a result allow the label to take on the correct height. _multilineLabel.preferredMaxLayoutWidth = CGRectGetWidth(_multilineLabel.frame); _title2Label.preferredMaxLayoutWidth = CGRectGetWidth(_title2Label.frame); _title3Label.preferredMaxLayoutWidth = CGRectGetWidth(title3Label.frame); _title4Label.preferredMaxLayoutWidth = CGRectGetWidth(_title4Label.frame); } if (self.heightCalculationInProgress) { self.layoutingLock = YES; } }