我正在使用Xcode4编写一个简单的iOS应用程序,它使用表格视图来显示故事列表(从URL获取)。我将故事标题显示为UILabels,并作为表格单元格的子视图。
我超越heightForRowAtIndexPath
根据每个故事标题的长度来计算单元格的正确高度。我正在cellForRowAtIndexPath
中将标签添加到单元格中。当我在模拟器中运行应用程序时,一切都很好。但是:当我向下滚动并向上滚动时,标签会搞砸。它们被截断并超载。我调试了一下,发现在滚动过程中没有触发heightForRowAtIndexPath
方法,因此不会重新计算单元格高度,因此标签文本会溢出,并且会变得难看。以下是相关代码:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:@"Cell"];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
[cell autorelease];
}
/* NOTE: code to load trimmedTitle dynamically is snipped */
NSString* trimmedTitle;
UIFont *cellFont = [UIFont fontWithName:@"Georgia" size:14.0];
CGSize constraintSize = CGSizeMake(280.0f, MAXFLOAT);
CGSize labelSize = [trimmedTitle sizeWithFont:cellFont constrainedToSize:constraintSize
lineBreakMode:UILineBreakModeWordWrap];
UILabel* tempLabel = [[UILabel alloc] initWithFrame:CGRectMake(60, 0, 230, labelSize.height)];
tempLabel.lineBreakMode = UILineBreakModeWordWrap;
tempLabel.text = trimmedTitle;
tempLabel.numberOfLines = 0;
[cell.contentView addSubview:tempLabel];
[tempLabel release];
return cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString* cellText; // code to load cellText dynamically is snipped off
UIFont *cellFont = [UIFont fontWithName:@"Georgia" size:14.0];
CGSize constraintSize = CGSizeMake(230.0f, MAXFLOAT);
CGSize labelSize = [cellText sizeWithFont:cellFont constrainedToSize:constraintSize lineBreakMode:UILineBreakModeWordWrap];
return labelSize.height + 20;
}
答案 0 :(得分:2)
在这些情况下,我通常预先计算所有行的高度,将它们存储在一个数组中,然后只返回heightForRowAtIndexPath
中的那些高度。这样,tableview知道每个单元格的高度,并且即使在重用之后单元格也符合该高度。我不知道一种强制计算单元格高度的方法,除了查找单元格何时可以查看并重新加载它时,这看起来太昂贵了。
更新:一些示例代码:
我有一个名为- (void)calculateHeights
的方法,它执行与heightForRowAtIndexPath
中相同的计算,但将结果存储在我的可变数组heights_
中ivar:
- (void)calculateHeights {
[heights_ removeAllObjects]
for (Widget *myWidget in modelWidgetArray) {
NSString* cellText; // code to load cellText dynamically is snipped off
UIFont *cellFont = [UIFont fontWithName:@"Georgia" size:14.0];
CGSize constraintSize = CGSizeMake(230.0f, MAXFLOAT);
CGSize labelSize = [cellText sizeWithFont:cellFont constrainedToSize:constraintSize lineBreakMode:UILineBreakModeWordWrap];
[heights_ addObject:[NSNumber numberWithFloat:labelSize.height + 20.0f]];
}
}
然后在heightForRowAtIndexPath
中给出一个1节的表视图:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return [heights_ objectAtIndex:[indexPath row]];
}
如果您的表视图有多个部分,您需要进行一些数学运算才能转换为一维heights_
数组并再次返回。此外,只要您-reloadData
,您也需要-calculateHeights
。
答案 1 :(得分:0)
在编写滚动视图之前调用-tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
方法。
在调用-tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
之前调用此方法但在滚动期间未触发的目的是表视图(继承自UIScrollView )需要知道contentView的整个高度。一旦表格视图知道所有高度,它就会在您调用-reloadData
您的问题意味着您需要清除单元格-prepareForReuse
中的内容,并调用-setNeedLayout
来布置所有新内容。
答案 2 :(得分:0)
您可以使用标记作为标签,以避免互相混淆
UILabel *label= (UILabel*)[cell viewWithTag:2];
label.lineBreakMode = UILineBreakModeWordWrap;
label.numberOfLines = 0;