【发布时间】:2013-03-20 01:41:09
【问题描述】:
我在视图中有一个 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];
}
我使用我的数据对象动态配置单元格,然后调用我拥有的一个方法来计算具有给定表格宽度的单元格的高度(不能总是依赖最初正确的单元格框架) .
这反过来又在我的视图中调用了一个 height 方法,因为它确实是标签所在的位置:
- (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];
}
}
一种解决方案,但我不明白为什么
- 我的子视图设计为 320 宽度,但没有自己的宽度限制
- 子视图已添加到单元格中,但具有如下所示的水平约束:
@"|[_thirdPartyAnswerView]-38-|"
- 视图是在添加到单元格后立即配置的,这意味着 titleLabel 的文本是在那时设置的。
- 无论出于何种原因,文本的布局都好像视图具有完整的 320 而不是 282。
- 标签从未更新,即使子视图的框架已更新为 282,并且标签上有一些约束可以使其保持正确的大小。
- 将 xib 中的视图大小更改为 282 可解决此问题,因为标签的开头大小正确。
我仍然不明白为什么在父视图的大小更新后标签没有重新布局,因为它同时具有前导和尾随约束。
已解决
请看下面马特的回答:https://stackoverflow.com/a/15514707/287403
如果您没有阅读评论,主要问题是我在设计宽度大于显示宽度的视图时(在某些情况下)通过 IB 在不知不觉中设置了preferredMaxLayoutWidth。 preferredMaxLayoutWidth 用于确定文本换行的位置。因此,即使我的视图和 titleLabel 正确调整了大小,preferredMaxLayoutWidth 仍处于旧值,并导致在意外点处换行。将 titleLabel 设置为自动大小(IB 中的⌘=),并在调用 super 之前在 layoutSubviews 中动态更新 preferredMaxLayoutWidth 是关键。谢谢马特!
【问题讨论】:
-
您是否尝试在渲染期间捕获此单元格以查看所有属性?作为后续,在初始屏幕上呈现的单元格是否会发生这种情况?对于具有不同高度单元格的列表视图,我遇到了类似的问题。启用自动调整大小后,单元格有时会错误地呈现高度。
-
与细胞重复使用有任何联系吗?例如单元格滚动出站点并返回 - 效果与以前一样吗?单元格是在该 tableview 最初可见的过去绘制的,效果还是一样吗? ...
-
无连接可重复使用。如果立即绘制或稍后滚动,结果相同。
-
你救了我的命,伙计! preferredMaxLayoutWidth 正在杀死它
标签: ios autolayout