Ios 自动布局多行UILabel剪切某些文本
我正在努力学习自动布局,最后我认为这件事发生时我已经掌握了窍门。我在玩弄原型细胞和标签。我正试着有一个Ios 自动布局多行UILabel剪切某些文本,ios,objective-c,uilabel,autolayout,uistoryboard,Ios,Objective C,Uilabel,Autolayout,Uistoryboard,我正在努力学习自动布局,最后我认为这件事发生时我已经掌握了窍门。我在玩弄原型细胞和标签。我正试着有一个 标题,标题BL-图片中的蓝色框 货币,moneyLbl-图片中的绿色方框 副标题/说明,副标题LBL-图片中的红色框 到目前为止,我有: 我想要实现的是: 绿色框应始终完全显示在一行上 绿色框内的值应基于蓝色框居中 蓝色框将占用剩余空间(-8px表示2之间的水平约束),并在必要时显示在多行上 红色框应位于下方,并根据需要显示尽可能多的行 正如您所看到的,除了最后一行中的示例之外,这几
- 标题,
-图片中的蓝色框标题BL
- 货币,
-图片中的绿色方框moneyLbl
- 副标题/说明,
-图片中的红色框副标题LBL
- 绿色框应始终完全显示在一行上
- 绿色框内的值应基于蓝色框居中
- 蓝色框将占用剩余空间(-8px表示2之间的水平约束),并在必要时显示在多行上
- 红色框应位于下方,并根据需要显示尽可能多的行
setPreferredMaxLayoutWidth
,我在多个地方为titlebl
做过这样的设置,但没有效果。只有将其硬编码为180
时,我才得到结果,但它还为文本顶部/底部的其他蓝色框添加了空格/填充,大大增加了红色/蓝色框之间的空间
以下是我的限制:
标题:
金钱:
副标题:
根据我对其他文本示例运行的测试,它似乎使用了故事板中显示的宽度,但任何纠正它的尝试都不起作用
我已经创建了单元格的ivar,并使用它来创建单元格的高度:
- (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];
}
日志:
这就是我所期望的,因为这两个元素之间有8px,控制台验证了这一点。无论我在蓝色框中添加了多少文本,它都能在第一行上完美地工作,蓝色框与情节提要相同,但绿色框的任何增加都会影响宽度计算。我已经尝试在表格视图:willDisplayCell
和表格视图:heightForRowAtIndexPath:
中根据其他问题的答案进行设置。但不管怎么说,它都无法布局
如果您能提供任何帮助、想法或意见,我们将不胜感激。我不确定是否正确理解您的意思,我的解决方案确实远不是最好的,但这里是: 我在被剪切的标签上添加了一个高度约束,将该约束连接到单元格的出口。我已重写layoutSubview方法:
- (void) layoutSubviews {
[super layoutSubviews];
[self.badLabel setNeedsLayout];
[self.badLabel layoutIfNeeded];
self.badLabelHeightConstraint.constant = self.badLabel.intrinsicContentSize.height;
}
还有维奥拉!请尝试这种方法并告诉我结果,谢谢。阅读此文后找到了更好的答案: 创建
UILabel
子类以覆盖layoutSubviews
如下所示:
- (void)layoutSubviews
{
[super layoutSubviews];
self.preferredMaxLayoutWidth = CGRectGetWidth(self.bounds);
[super layoutSubviews];
}
这可确保首选MaxLayoutWidth
始终正确
更新:
在又发布了几次iOS并测试了更多用例之后,我发现上述内容并不足以满足所有情况。截至iOS 8(我相信),在某些情况下,只有didSet
bounds
在屏幕加载之前被及时调用
最近在iOS 9中,我遇到了另一个问题,当使用带有UITableView
的模态UIVIewController
时,layoutSubviews
和set bounds
都在高度之后被调用。经过大量调试后,唯一的解决方案是覆盖设置帧
下面的代码现在似乎是必要的,以确保它在所有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
}
}
天哪,我也有同样的问题。@Simon McLoughlin的回答对我没有帮助。但是
titleLabel.adjustsFontSizeToFitWidth = true
你变魔术了!这很有效,我不知道为什么,但确实有效。
是的,您的标签也必须有一个明确的preferredMaxLayoutWidth值。我确实花了一些时间包装单元格,如下所示:
+--------------------------------------------------+
| This is my cell.contentView |
| +------+ +-----------------+ +--------+ +------+ |
| | | | multiline | | title2 | | | |
| | img | +-----------------+ +--------+ | img | |
| | | +-----------------+ +--------+ | | |
| | | | title3 | | title4 | | | |
| +------+ +-----------------+ +--------+ +------+ |
| |
+--------------------------------------------------+
[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
}];
经过多次尝试,我终于找到了一个解决方案,如何使用实际工作的原型电池
主要的问题是我的标签可能在那里,也可能不在那里。
每个元素都应该是可选的
首先,当我们不在“真实”环境中时,我们的“原型”单元应该只布局东西
因此,我创建了标志“HeightCalculationProgress”
当有人(tableView的数据源)要求计算高度时,我们使用块向原型单元提供数据:
然后我们要求我们的原型单元对内容进行布局,并从中获取高度。简单
为了避免layoutSubview递归出现iOS7错误,有一个“layoutingLock”变量
从外部看,此“块”可能如下所示:
+--------------------------------------------------+
| This is my cell.contentView |
| +------+ +-----------------+ +--------+ +------+ |
| | | | multiline | | title2 | | | |
| | img | +-----------------+ +--------+ | img | |
| | | +-----------------+ +--------+ | | |
| | | | title3 | | title4 | | | |
| +------+ +-----------------+ +--------+ +------+ |
| |
+--------------------------------------------------+
[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;
}
}
谢谢你的意见,但我很抱歉,这太离谱了。问题(如我的回答所述)是,在绿色标签伸展以适应其内容之前,它使用了绿色标签的X
位置。在大多数情况下使用多行标签时,需要设置setPreferredMaxLayoutWidth
,我需要计算绿色的显示宽度,以便计算蓝色的此值。一旦设置好,它就计算出了正确的高度。这不是一个理想的解决方案。而不是让标签增长,这只是让字体增加/减少,以适应固定的宽度。这将导致您的UI看起来非常不一致。我在iOS和需要额外代码的用例中发现了更多的bug。我更新了上面的答案。