UILabel 有时不能正确换行(自动布局) [英] UILabel not wrapping text correctly sometimes (auto layout)

查看:86
本文介绍了UILabel 有时不能正确换行(自动布局)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a uilabel setup in a view. It doesn't have a width constraint, but its width is instead determined by a leading constraint to the thumbnail image, and a trailing constraint to the edge of the view.

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

The label is set to have 0 lines, and to word wrap. My understanding is that this should cause the frame of the uilabel to grow, and indeed it does sometimes. (Previous to auto layout, I would calculate and update the frame of the label in code).

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

So the result is, it works correctly in some instance and not others. See most cells working correctly there, but the last cell appears to be too big. In fact it's the right size. The title "Fair Oaks Smog Check Test" actually ends with "Only". So my calcuation for the cell size is right, it should be that size. However the label doesn't wrap the text for whatever reason. It's frame width does not extend off to the right, so that's not the issue.

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

So what is going on here? It's 100% consistent, always on that cell and not the ones above it, which makes me think it's related to the size of the text, and UILabel isn't re-laying out the text once this view is added to the cell (which makes it actually smaller width wise).

有什么想法吗?

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

The height of the cells is calculated from one sample cell I create and store in a static variable:

- (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];
}

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

I configure the cell with my data object on the fly, and then call a method I have on it which calculates the height of the cell with a given table width (can't always rely on the cell frame being correct initially).

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

This in turn calls a height method on my view, since it is really where the label lives:

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

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

This method determines the height by figuring out the correct width of the label, and then doing a calculation:

- (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 中创建并立即配置的:

The cells are created obviously in cellForRowAtIndexPath and immediately configured:

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

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

In configuration of the cell, my view is loaded from a nib (it's re-used elsewhere, which is why it's not directly in the cell). The cell adds it as follows:

- (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];
}

最后我的视图配置是这样的:

Finally my view configuration looks like this:

- (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-|"

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

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

See Matt's answer below: https://stackoverflow.com/a/15514707/287403

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

In case you don't read the comment, the primary problem was that I was unknowingly setting preferredMaxLayoutWidth via IB when designing a view at a bigger width than it would be shown (in some cases). preferredMaxLayoutWidth is what is used to determine where the text wraps. So even though my view and titleLabel correctly resized, the preferredMaxLayoutWidth was still at the old value, and causing wrapping at unexpected points. Setting the titleLabel instead to it's automatic size (⌘= in IB), and updating the preferredMaxLayoutWidth dynamically in layoutSubviews before calling super was the key. Thanks Matt!

推荐答案

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

I'm someone who has written an app that uses autolayout of five labels in a cell in a table whose cells have different heights, where the labels resize themselves according to what's in them, and it does work. I'm going to suggest, therefore, that the reason you're having trouble might be that your constraints are under-determining the layout - that is, that you've got ambiguous layout for the elements of the cell. I can't test that hypothesis because I can't see your constraints. But you can easily check (I think) by using po [[UIWindow keyWindow] _autolayoutTrace] when paused in the debugger.

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

Also I have one other suggestion (sorry to just throw stuff at you): make sure you're setting the label's preferredMaxLayoutWidth. This is crucial because it's the width at which the label will stop growing horizontally and start growing vertically.

这篇关于UILabel 有时不能正确换行(自动布局)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆