テーブル セルに多くのテキストと画像がある場合、テーブル セルの高さを決定する際に問題が発生します。しかし、問題は文脈依存であり、使用されるテキストの種類によって異なります。問題を説明し、セルの書式設定とセルの高さの決定に使用しているコードを示します。セルの左側に画像がある場合、画像とテキストの最大高さからセルの高さを取得しています。問題は、すべての状況で文字の高さが正しく計算されないことです。以下では、下のセルに次のテキストがあります。
“P 154 ベトナムの家庭料理: とても良い!! スパイスをブレンドしてペースト状にすると、うまくいきました。ズッキーニの残りのソースを使ってグリルしました。うまくいきました。厚いポークチョップ; 450 ~ 525 で 35 分間調理します。」
テーブル ビューが一番下までスクロールされます。ご覧のとおり、テキストの下部は存在しません (「450 ~ 525 で 35 分間加熱」)。実際に起こっていることは、テキスト幅が正しく決定されていないということです。以下では、テキスト幅は cell.textLabel.bounds.size.width: 234 ピクセルとして計算されています。これに基づいて、テキストの高さが正しく計算されません。
ただし、アクセサリ ボタン (「>」) を押して次のビューに移動し、そのビューから (ナビゲーション コントローラーで「戻る」ボタンを使用して) 戻ると、通常は次のように変更されたテーブル表示が表示されます (ただし、場合によっては、残りのテキストなしで上記のビューを取得します):
この場合、テーブル ビューが 2 回目に表示されるときに、テキストの幅は cell.textLabel.bounds.size.width: 163 ピクセルとして計算されます。2 つのテキスト幅の差 (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 内の正しい幅に強制することでした。ただし、これは確かにハックです。より良い解決策が欲しいです。アイデア?
コード
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;
}
}