UILabel有时不包装文本(自动布局)
我在视图中设置了一个uilabel。 它没有宽度约束,但其宽度取决于对缩略图图像的前导约束和对视图边缘的尾随约束。
标签被设置为0行,并自动换行。 我的理解是,这应该导致uilabel框架成长,有时确实。 (在自动布局之前,我会计算并更新代码中标签的框架)。
所以结果是,它在某些情况下正常工作,而不是其他情况。 看到大多数细胞在那里正常工作,但最后一个细胞似乎太大了。 其实这是正确的大小。 标题“公平的橡木烟雾检查testing”实际上以“唯一”结束。 所以我的单元大小的计算是正确的,它应该是这样的大小。 然而,标签不会出于任何原因包装文本。 它的框架宽度不会延伸到右边,所以这不是问题。
那么这里发生了什么? 它是100%一致的,总是在那个单元格上,而不是在它上面,这使我认为它与文本的大小有关,并且UILabel在这个视图被添加到单元格之后不重新排列文本使其实际上更小的宽度明智)。
有什么想法吗?
一些额外的信息
单元格的高度是从我创build的一个样本单元计算的,并存储在一个静态variables中:
- (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]; }
我用dynamic数据对象configuration单元格,然后调用一个方法来计算具有给定表格宽度的单元格的高度(不能总是依赖最初的单元格框架是正确的)。
这反过来在我的观点上调用一个高度方法,因为它实际上是标签所在的地方:
- (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中创build的,并立即进行configuration:
if (self.items.count > 0) { TCAnswerBuilderCell *cell = [tableView dequeueReusableCellWithIdentifier:TC_ANSWER_BUILDER_CELL forIndexPath:indexPath]; [cell configureCellWithThirdPartyObject:self.items[indexPath.row]]; return cell; }
在单元格的configuration中,我的视图是从一个笔尖加载的(在其他地方重新使用它,这就是为什么它不直接在单元格中)。 该单元格添加如下:
- (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]; }
最后我的视图configuration如下所示:
- (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]; } }
一种解决scheme,但我不明白为什么
- 我的子视图的宽度devise为320,但对宽度没有限制
- 子视图被添加到单元格,但水平约束如下所示:
-
@"|[_thirdPartyAnswerView]-38-|"
-
- 视图是在添加到单元格后立即configuration的,这意味着titleLabel的文本已经设置好了。
- 无论出于何种原因,文本的布局似乎都是320而不是282。
- 即使子视图的框架已更新为282,标签也从未更新过,并且标签上的约束会使其尺寸保持正确。
- 更改xib中的视图的大小为282固定的问题,因为标签具有正确的大小开始。
我仍然不明白为什么在父视图的大小更新时,标签不会重新布局,因为它同时具有前导约束和尾随约束。
解决了
请参阅以下Matt的回答: https : //stackoverflow.com/a/15514707/287403
如果你没有阅读评论,主要的问题是,当我devise一个宽度比它显示的更宽的视图(在某些情况下)时,我不知不觉地通过IB设置preferredMaxLayoutWidth
。 preferredMaxLayoutWidth
是用来确定文本换行的地方。 因此,即使我的view和titleLabel正确resize, preferredMaxLayoutWidth
仍然是旧值,并导致意外的包装。 将titleLabel设置为自动resize(⌘=在IB中),并在调用super之前在layoutSubviews
dynamic更新preferredMaxLayoutWidth
是关键。 谢谢马特!
我写了一个应用程序,它在单元格高度不同的表格的单元格中使用五个标签的自动布局,其中标签根据其中的内容调整自己的大小,并且工作正常。 因此,我会build议你有困难的原因可能是你的约束不能确定布局 – 也就是说,你对单元的元素有着模糊的布局。 我无法检验这个假设,因为我看不到你的约束。 但是,在debugging器中暂停时,可以通过使用po [[UIWindow keyWindow] _autolayoutTrace]
来轻松检查(我认为)。
另外我还有一个build议(对不起,只是扔东西):确保你设置标签的preferredMaxLayoutWidth
。 这是至关重要的,因为这是标签停止水平生长并开始垂直生长的宽度。
我有同样的问题,并用这个答案的build议解决它。 在UILabel的一个子类中,我放置了这个代码:
- (void)layoutSubviews { [super layoutSubviews]; self.preferredMaxLayoutWidth = self.bounds.size.width; }
我不明白为什么这不是UILabel的默认行为,或者至less你为什么不能通过一个标志启用这种行为。
我有点担心preferredMaxLayoutWidth被设置在布局过程的中间,但我看不到一个简单的方法。
此外,请检查您是否将整数传递给代码中的布局约束。
对于我来说,经过一些计算(例如convertPoint:toView :)后,我传递了类似于23.99999997的东西,最终这导致了一个2行标签显示为单行(虽然其框架似乎计算正确) 。 在我的情况CGRectIntegral做了诡计!
舍入错误可能会杀死你:)