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。我更新了上面的答案。