41

我在视图中有一个 uilabel 设置。它没有宽度约束,但它的宽度由缩略图图像的前导约束和视图边缘的尾随约束确定。

在此处输入图像描述

标签设置为 0 行,并自动换行。我的理解是,这应该会导致 uilabel 的框架增长,而且有时确实会增长。(在自动布局之前,我会在代码中计算和更新标签的框架)。

所以结果是,它在某些情况下可以正常工作,而在其他情况下不能正常工作。看到大多数单元格在那里正常工作,但最后一个单元格似乎太大了。事实上,它的大小是合适的。标题“Fair Oaks Smog Check Test”实际上以“Only”结尾。所以我对单元格大小的计算是正确的,应该是那个大小。但是,无论出于何种原因,标签都不会包装文本。它的框架宽度没有向右延伸,所以这不是问题。

在此处输入图像描述

那么这里发生了什么?它是 100% 一致的,总是在那个单元格上而不是在它上面的那个单元格上,这让我认为它与文本的大小有关,一旦这个视图被添加到单元格中,UILabel 就不会重新布局文本(其中使它实际上在宽度方面更小)。

有什么想法吗?

一些附加信息

单元格的高度是根据我创建并存储在静态变量中的一个样本单元格计算的:

- (CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    if (self.items.count == 0) {
        return 60;
    }
    static TCAnswerBuilderCell *cell = nil;
    static dispatch_once_t pred;

    dispatch_once(&pred,
                  ^{
                      // get a sample cellonce
                      cell = [tableView dequeueReusableCellWithIdentifier:TC_ANSWER_BUILDER_CELL];
                  });
    [cell configureCellWithThirdPartyObject:self.items[indexPath.row]];
    return [cell heightForCellWithTableWidth:self.tableView.frame.size.width];
}

我使用我的数据对象动态配置单元格,然后调用我拥有的一个方法,该方法计算具有给定表格宽度的单元格的高度(不能总是依赖最初正确的单元格框架)。

这反过来又在我看来调用了一个高度方法,因为它确实是标签所在的位置:

- (CGFloat)heightForCellWithTableWidth:(CGFloat)tableWidth {
    // subtract 38 from the constraint above
    return [self.thirdPartyAnswerView heightForViewWithViewWidth:tableWidth - 38];
}

该方法通过计算出标签的正确宽度来确定高度,然后进行计算:

- (CGFloat)heightForViewWithViewWidth:(CGFloat)viewWidth {
    CGFloat widthForCalc = viewWidth - self.imageFrameLeadingSpaceConstraint.constant - self.thumbnailFrameWidthConstraint.constant - self.titleLabelLeadingSpaceConstraint.constant;
    CGSize size = [self.titleLabel.text sizeWithFont:self.titleLabel.font constrainedToSize:CGSizeMake(widthForCalc, CGFLOAT_MAX) lineBreakMode:NSLineBreakByWordWrapping];
    CGFloat returnHeight = self.frame.size.height - self.titleLabel.frame.size.height + size.height;
    CGFloat height = returnHeight < self.frame.size.height ? self.frame.size.height : returnHeight;
    return height;
}

这可以 100% 正确工作。

单元格显然是在 cellForRowAtIndexPath 中创建并立即配置的:

if (self.items.count > 0) {
    TCAnswerBuilderCell *cell = [tableView dequeueReusableCellWithIdentifier:TC_ANSWER_BUILDER_CELL forIndexPath:indexPath];
    [cell configureCellWithThirdPartyObject:self.items[indexPath.row]];
    return cell;
}

在单元格的配置中,我的视图是从笔尖加载的(它在其他地方被重新使用,这就是它不直接在单元格中的原因)。单元格将其添加如下:

- (void) configureCellWithThirdPartyObject:(TCThirdPartyObject *)object {
    self.detailDisclosureImageView.hidden = NO;
    if (!self.thirdPartyAnswerView) {
        self.thirdPartyAnswerView = [TCThirdPartyAPIHelper thirdPartyAnswerViewForThirdPartyAPIServiceType:object.thirdPartyAPIType];
        self.thirdPartyAnswerView.translatesAutoresizingMaskIntoConstraints = NO;
        [self.contentView addSubview:self.thirdPartyAnswerView];
        [self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"|[_thirdPartyAnswerView]-38-|" options:NSLayoutFormatAlignAllCenterY metrics:nil views:NSDictionaryOfVariableBindings(_thirdPartyAnswerView)]];
    }
    [self.thirdPartyAnswerView configureViewForThirdPartyObject:object forViewStyle:TCThirdPartyAnswerViewStyleSearchCell];
}

最后我的视图配置如下所示:

- (void) configureViewForThirdPartyObject:(TCTPOPlace *)object forViewStyle:(TCThirdPartyAnswerViewStyle) style {
    self.titleLabel.text = object.name;
    self.addressLabel.text = [NSString stringWithFormat:@"%@, %@, %@", object.address, object.city, object.state];
    self.ratingsLabel.text = [NSString stringWithFormat:@"%d Ratings", object.reviewCount];
    NSString *ratingImageName = [NSString stringWithFormat:@"yelp_star_rating_%.1f.png", object.rating];
    UIImage *ratingsImage = [UIImage imageNamed:ratingImageName];
    if (ratingsImage) {
        self.ratingImageView.image = ratingsImage;
    }
    if (object.imageUrl) {
        [self.thumbnailImageView setImageWithURL:[NSURL URLWithString:object.imageUrl] completed:nil];
    }
}

一种解决方案,但我不明白为什么

  1. 我的子视图设计为 320 宽度,但没有自己的宽度限制
  2. 子视图已添加到单元格中,但具有如下所示的水平约束:
    • @"|[_thirdPartyAnswerView]-38-|"
  3. 视图是在添加到单元格后立即配置的,这意味着 titleLabel 的文本是在那时设置的。
  4. 无论出于何种原因,文本的布局好像视图具有完整的 320 而不是 282。
  5. 标签从未更新,即使子视图的框架已更新为 282,并且标签上存在保持其大小正确的约束。
  6. 将 xib 中的视图大小更改为 282 可以解决此问题,因为标签的开头大小正确。

我仍然不明白为什么在父视图的大小更新后标签没有重新布局,因为它同时具有前导约束和尾随约束。

解决了

请参阅下面的马特回答:https ://stackoverflow.com/a/15514707/287403

如果您没有阅读评论,主要问题是我preferredMaxLayoutWidth在设计宽度大于显示宽度的视图时(在某些情况下)是在不知不觉中通过 IB 设置的。preferredMaxLayoutWidth用于确定文本换行的位置。因此,即使我的 view 和 titleLabel 正确调整了大小,它preferredMaxLayoutWidth仍然是旧值,并导致在意外点处换行。将 titleLabel 设置为自动大小(IB 中的⌘=),并在调用 super 之前preferredMaxLayoutWidth动态更新 in是关键。layoutSubviews谢谢马特!

4

3 回答 3

43

我是一个编写了一个应用程序的人,该应用程序在表格中的一个单元格中使用五个标签的自动布局,其单元格具有不同的高度,其中标签根据其中的内容调整自身大小,并且确实有效。因此,我将建议您遇到问题的原因可能是您的约束未充分确定布局 - 也就是说,您的单元格元素布局不明确。我无法检验该假设,因为我看不到您的限制。po [[UIWindow keyWindow] _autolayoutTrace]但是您可以通过在调试器中暂停时使用来轻松检查(我认为) 。

另外我还有另一个建议(很抱歉只是向你扔东西):确保你设置标签的preferredMaxLayoutWidth. 这很关键,因为它是标签停止水平增长并开始垂直增长的宽度。

于 2013-03-20T03:22:08.520 回答
13

我遇到了同样的问题,并使用此答案中的建议解决了它。在 UILabel 的子类中,我放置了以下代码:

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

我不明白为什么这不是 UILabel 的默认行为,或者至少为什么不能通过标志启用此行为。

我有点担心在布局过程中设置了preferredMaxLayoutWidth,但我认为没有简单的方法。

于 2013-11-13T18:29:11.560 回答
0

此外,请检查您是否将整数传递给代码中的布局约束。

对我来说,经过一些计算(例如 convertPoint:toView:),我传递了类似 23.99999997 的东西,最终这导致一个 2 行标签显示为单行标签(尽管它的框架似乎计算正确) . 就我而言,CGRectIntegral 成功了!

舍入错误可能会杀死你:)

于 2017-10-20T13:58:58.197 回答