当表格单元格有很多文本和图像时,我在确定表格单元格的高度时遇到了问题。但问题是上下文相关的,取决于所使用的文本类型。我将解释这个问题,然后给出我用来格式化单元格和确定单元格高度的代码。当我在单元格左侧有一个图像时,我从图像的最大高度与文本的最大高度中获取单元格高度。问题是在所有情况下都没有正确计算文本高度。下面,我在底部单元格中有以下文本:
“P 154 越南家常菜:非常好!!将香料搅拌成糊状——效果很好;用西葫芦上剩下的酱汁烤;运作良好;厚猪排;在 450 和 525 之间煮 35 分钟”。
表格视图一直滚动到底部。如您所见,文本的底部不存在(“在 450 和 525 之间煮 35 分钟”)。实际发生的情况是没有正确确定文本宽度。下面,文本宽度被计算为 cell.textLabel.bounds.size.width: 234 像素。基于此,错误地计算了文本的高度。
但是,如果我按下辅助按钮 (“>”) 并进入下一个视图,然后从该视图返回(使用带有导航控制器的“后退”按钮),我通常会得到以下更改的表格显示(但有时我仍然得到上面的视图,没有剩余的文字):
在这种情况下,表格视图第二次显示时,文本的宽度计算为 cell.textLabel.bounds.size.width: 163 像素。两个文本宽度之间的差异(234 - 163 = 71 像素)。图像宽度为 100 像素。不幸的是,情况比这更复杂:
1)如果单元格中没有图像,我确定文本的宽度没有问题。
2)如果我只使用一系列简单的文本行,例如一系列连续的数字/字母,每个字符后都有一个回车符,那么宽度是正确确定的。例如,如果单元格中的文本是:
1
2
3
4
5
6
7
8
9
0
A
B
C
3)如果单元格后面(下面)有大量整行文本(不是由回车后跟字符组成的文本)的单元格,那么我永远不会正确计算单元格宽度(因此高度永远不会计算正确)。
我尝试了什么?
在 cellForRowAtIndexPath 中,我尝试过: cell.textLabel.autoresizingMask = UIViewAutoresizingNone; 正如所有方向中 UITableViewCell 中的 Dynamic UILabel Heights/Widths所建议的那样,但这并没有改变这种情况。
我还尝试从计算 UILabel/UITableViewCell 的多行文本高度:计算与实际绘制到 cellForRowAtIndexPath 时的不同结果中的建议,这会强制文本标签的新宽度,但这不起作用。
一个有效的黑客
起作用的是强制文本标签宽度为 heightForRowAtIndexPath 内的正确宽度。但是,这肯定是一个hack。我想要一个更好的解决方案。想法?
代码
在 BUG74 之后的代码中是我在这里描述的问题。
// https://stackoverflow.com/questions/129502/how-do-i-wrap-text-in-a-uitableviewcell-without-a-custom-cell
- (UITableViewCell *)tableView:(UITableView *)theTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"CustomCellCommentList";
CustomCell *cell = (CustomCell*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
NSLog(@"CommentList.cellForRowAtIndexPath: nil case");
cell = [[CustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
IF_IOS6_OR_GREATER(
cell.textLabel.lineBreakMode = NSLineBreakByWordWrapping;
);
IF_LESS_THAN_IOS6(
cell.textLabel.lineBreakMode = UILineBreakModeWordWrap;
);
// To remove any maximum limit, and use as many lines as needed, set the value of this property to 0.
cell.textLabel.numberOfLines = 0;
cell.textLabel.font = [UIFont fontWithName:@"Helvetica" size:17.0];
cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
cell.textLabel.autoresizingMask = UIViewAutoresizingNone;
}
NSDictionary *menuItemCommentDictionary =
[Globals GetIthMenuItemComment: indexPath.row forMenuItem: menuItemName andRestaurant: restaurantName];
//NSDate *commentDate = [menuItemCommentDictionary objectForKey:@"date"];
if (CommentListDebug) NSLog(@"cellForRowAtIndexPath");
UIImage *theIcon;
NSString *imageFileName = [menuItemCommentDictionary objectForKey:COMMENT_KEY_IMAGE_FILENAME];
if (imageFileName) {
// Scaling images in table view cells
// https://stackoverflow.com/questions/9046573/uitableviewcell-resize-image
#define DEFAULT_TABLE_CELL_HEIGHT 44
#define IMAGE_WIDTH_IN_TABLE_CELL 100
/* I'm going to give images a constant width and adjust
the height of the table cell according to their height.
*/
theIcon = [PersistentStorage retrieveIconFromFile:imageFileName];
if (CommentListDebug) NSLog(@"icon: %@", theIcon);
//NSNumber *iconHeight = [menuItemCommentDictionary objectForKey:@"imageIconHeight"];
//if (CommentListDebug) NSLog(@"iconHeight: %d", [iconHeight intValue]);
cell.imageView.image = theIcon;
} else {
if (CommentListDebug) NSLog(@"No image file name");
cell.imageView.image = nil; // Otherwise, if using old cell, uses old icon image
}
NSString *cellText = [menuItemCommentDictionary objectForKey:@"menuItemComment"];
// 1/5/13; Bug# 62; only if there is no icon/image and no text
// should we mark as empty.
if ((! imageFileName) && ((nil == cellText) || ([cellText length] == 0))) {
cellText = EMPTY_TEXT; // temporary empty text
}
cell.textLabel.text = cellText;
// BUG74: 1/29/13;
// We are not having problems with the text width when there
// is no icon, so only do this when there is an icon
// NOTE: This does *not* work; for some reason, the frame.size.width
// is not retained in the call to heightForRowAtIndexPath.
if (imageFileName) {
CGRect labelFrame = cell.textLabel.frame;
labelFrame.size.width = 287 - 27 - theIcon.size.width;
NSLog(@"CommentList.cellForRowAtIndexPath: labelFrame.size.width: %d", (int) labelFrame.size.width);
cell.textLabel.frame = labelFrame;
[cell.textLabel sizeToFit];
}
return cell;
}
- (CGFloat)tableView:(UITableView *)thisTableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSDictionary *menuItemCommentDictionary =
[Globals GetIthMenuItemComment: indexPath.row forMenuItem: menuItemName andRestaurant: restaurantName];
NSString *cellText = [menuItemCommentDictionary objectForKey:@"menuItemComment"];
// 1/5/13; Bug# 62; I'm going to allow empty comments in the case
// where there is no picture and no text. This is to allow a user
// to have a smiley rating only but no picture and no text.
// The issue here is that with no text, the height of the row
// is too small, and looks odd. And it's hard to select that row to
// delete because it's not very tall.
// My fix for this it to add some temporary empty text. I've used
// non-white space text, because I still get the issue if I use
// white space. If I add the display of smiley's in the comment
// list then this issue should go away).
// For some reason the cellText does not seem to be nil when there
// is no text.
if ((nil == cellText) || ([cellText length] == 0)) {
cellText = EMPTY_TEXT; // temporary empty text
}
//NSDate *commentDate = [menuItemCommentDictionary objectForKey:@"date"];
NSString *imageFileName = [menuItemCommentDictionary objectForKey:COMMENT_KEY_IMAGE_FILENAME];
// If I directly retrieve the icon from the file and display it
// that way, I get a mess! The image is much too large!!
UIImage *theIcon = nil;
if (imageFileName) {
theIcon = [PersistentStorage retrieveIconFromFile:imageFileName];
}
UIFont *cellFont = [UIFont fontWithName:@"Helvetica" size:17.0];
// Some of the following code modified from:
//https://stackoverflow.com/questions/1947970/dynamic-calculation-of-uilabel-width-in-uitableviewcell
// Find the cell for this index path
UITableViewCell *cell = [self tableView:thisTableView cellForRowAtIndexPath:indexPath];
//CGFloat cellHeight = cell.frame.size.height;
// Calculate text size after forcing a layout
[cell layoutIfNeeded];
//CGSize textSize = [cell.textLabel.text sizeWithFont:cellFont constrainedToSize:CGSizeMake(cell.contentView.bounds.size.width, MAXFLOAT) lineBreakMode:cell.textLabel.lineBreakMode];
NSLog(@"CommentList.heightForRowAtIndexPath: cell.textLabel.bounds.size.width: %d", (int) cell.textLabel.bounds.size.width);
// In my tests, bounds.size.width is the same as frame.size.width
NSLog(@"CommentList.heightForRowAtIndexPath: cell.textLabel.frame.size.width: %d", (int) cell.textLabel.frame.size.width);
// cell.contentView.bounds.size.width gives the full width of the
// cell contents, which was 287 pixels when I tested it
if (CommentListDebug) NSLog(@"CommentList.heightForRowAtIndexPath: cell.contentView.bounds.size.width: %d", (int) cell.contentView.bounds.size.width);
// parameters to CGSizeMake are: width, height
// the width parameter here is supposed to be the text width;
CGSize constraintSize;
if (theIcon) {
// Start hack for BUG74; 1/29/13
// The number 27 just works; Is it the width of the
// accessory button within the cell?
// cell.contentView.bounds.size.width was 287 when I checked.
int textWidth = cell.contentView.bounds.size.width - 27 - theIcon.size.width;
constraintSize = CGSizeMake(textWidth, MAXFLOAT);
// End hack for BUG74; 1/29/13
} else {
constraintSize = CGSizeMake(cell.textLabel.bounds.size.width, MAXFLOAT);
}
CGSize labelSize = [cellText sizeWithFont:cellFont constrainedToSize:constraintSize lineBreakMode:cell.textLabel.lineBreakMode];
//NSNumber *iconHeight = [menuItemCommentDictionary objectForKey:@"imageIconHeight"];
#define LABEL_HEIGHT_EXTRA 20
#define ICON_HEIGHT_EXTRA 10
int textHeight = labelSize.height + LABEL_HEIGHT_EXTRA;
if (theIcon) {
//if ([iconHeight intValue] > 0) {
// Add 10 EXTRA here to give some white space between icons;
// with no white space, it can be hard to tell where one icon
// starts and where another ends, particularly because
// icons have variable height.
int iconHeight = ((int) theIcon.size.height) + ICON_HEIGHT_EXTRA;
/* if (CommentListDebug) */NSLog(@"CommentList.heightForRowAtIndexPath: icon height: %d; icon width: %d", (int) theIcon.size.height, (int) theIcon.size.width);
// BUG74: 1/28/13; If the text height is taller than the image
// height use the text height as the cell height.
NSLog(@"CommentList.heightForRowAtIndexPath: iconHeight= %d, textHeight= %d", iconHeight, textHeight);
if (iconHeight >= textHeight) return iconHeight;
return textHeight;
//return [iconHeight intValue] + 10;
} else {
// No image; use label size for height.
return textHeight;
}
}