UITableView 单元格内容未正确显示
Posted
技术标签:
【中文标题】UITableView 单元格内容未正确显示【英文标题】:UITableView cell contents not displayed properly 【发布时间】:2014-01-31 06:54:21 【问题描述】:我使用自动布局并希望在自定义单元格中显示 UITableView
,该单元格具有带有可变内容的 UITextView
。
单元格显示如下。对于聊天消息,当第一次显示单元格时单行仅显示 2-3 个字符,并且下一个字符被强制转到下一行。但是,当我滚动 tableView 以使这些单元格不可见并向后滚动以使它们可见时(我这样做是为了当它们再次可见时 cellForRowAtIndexPath: 方法被再次调用以渲染单元格),它们正确地渲染单元格,如图所示第二张图片。
代码:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
return 1;
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
return [chatData count];
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
RS_User *user = [[RS_User alloc]init];
chatCell *cell = (chatCell *)[tableView dequeueReusableCellWithIdentifier:CHAT_CELL_IDENTIFIER];
NSUInteger row = indexPath.row;
cell.chatCellBackground.image = nil;
NSString *chatText = [[chatData objectAtIndex:row] objectForKey:TEXT]; // get text string(message) from array
cell.textLabel.lineBreakMode = NSLineBreakByWordWrapping;
UIFont *font = [UIFont systemFontOfSize:FONT_SIZE];
cell.textString.font = [UIFont fontWithName:FONT_NAME size:FONT_SIZE]; // set text font
cell.textString.text = chatText;
// set text
CGSize size = [cell.textString.text sizeWithFont:cell.textString.font constrainedToSize:CGSizeMake(SET_WIDTH, MAXFLOAT) lineBreakMode:NSLineBreakByCharWrapping];
cell.textString.frame = ...;
[cell.textString sizeToFit];
NSDate *theDate = [[chatData objectAtIndex:row] objectForKey:DATE];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:DATE_FORMAT];
NSString *timeString = [formatter stringFromDate:theDate];
cell.timeLabel.text = timeString; // set timeLabel to display date and time
cell.timeLabel.font = [UIFont fontWithName:FONT_NAME size:SMALL_FONT_SIZE];
cell.userLabel.text = @"Name";//[[chatData objectAtIndex:row] objectForKey:NAME]; // set userLabel to display userName
CGSize size1 = [cell.userLabel.text sizeWithFont:font constrainedToSize:CGSizeMake(SET_WIDTH, MAXFLOAT) lineBreakMode:NSLineBreakByCharWrapping];
// check cell contains sender name or receiver name
if (thisCellIsForSender)
// Set bubble for sender
cell.chatCellBackground.image = [[UIImage imageNamed:@"bubbleMine.png"] stretchableImageWithLeftCapWidth:STRETCHED_WIDTH topCapHeight:STRETCHED_HEIGHT];
cell.chatCellBackground.frame = ...;
else
// set bubble for receiver
cell.chatCellBackground.image = [[UIImage imageNamed:@"bubbleSomeone.png"] stretchableImageWithLeftCapWidth:STRETCHED_WIDTH topCapHeight:STRETCHED_HEIGHT];
cell.chatCellBackground.frame = ...;
[cell setNeedsLayout];
[cell layoutIfNeeded];
return cell;
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
RS_User *user = [[RS_User alloc]init];
chatCell *cell = (chatCell *)[tableView dequeueReusableCellWithIdentifier:CHAT_CELL_IDENTIFIER];
NSUInteger row = indexPath.row;
cell.chatCellBackground.image = nil;
NSString *chatText = [[chatData objectAtIndex:row] objectForKey:TEXT]; // get text string(message) from array
cell.textLabel.lineBreakMode = NSLineBreakByWordWrapping;
UIFont *font = [UIFont systemFontOfSize:FONT_SIZE];
cell.textString.font = [UIFont fontWithName:FONT_NAME size:FONT_SIZE]; // set text font
cell.textString.text = chatText;
// set text
CGSize size = [cell.textString.text sizeWithFont:cell.textString.font constrainedToSize:CGSizeMake(SET_WIDTH, MAXFLOAT) lineBreakMode:NSLineBreakByCharWrapping];
cell.textString.frame = ...;
[cell.textString sizeToFit];
NSDate *theDate = [[chatData objectAtIndex:row] objectForKey:DATE];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:DATE_FORMAT];
NSString *timeString = [formatter stringFromDate:theDate];
cell.timeLabel.text = timeString; // set timeLabel to display date and time
cell.timeLabel.font = [UIFont fontWithName:FONT_NAME size:SMALL_FONT_SIZE];
cell.userLabel.text = [[chatData objectAtIndex:row] objectForKey:NAME]; // set userLabel to display userName
[cell setNeedsUpdateConstraints];
[cell updateConstraintsIfNeeded];
CGSize size1 = [cell.userLabel.text sizeWithFont:font constrainedToSize:CGSizeMake(SET_WIDTH, MAXFLOAT) lineBreakMode:NSLineBreakByCharWrapping];
// check cell contains sender name or receiver name
if (thisCellIsForSender)
// Set bubble for sender
cell.chatCellBackground.image = [[UIImage imageNamed:@"bubbleMine.png"] stretchableImageWithLeftCapWidth:STRETCHED_WIDTH topCapHeight:STRETCHED_HEIGHT];
cell.chatCellBackground.frame = ...;
else
// set bubble for receiver
cell.chatCellBackground.image = [[UIImage imageNamed:@"bubbleSomeone.png"] stretchableImageWithLeftCapWidth:STRETCHED_WIDTH topCapHeight:STRETCHED_HEIGHT];
cell.chatCellBackground.frame = ...;
cell.bounds = CGRectMake(0.0f, 0.0f, CGRectGetWidth(tableView.bounds), CGRectGetHeight(cell.bounds));
[cell setNeedsLayout];
[cell layoutIfNeeded];
return cell.bounds.size.height;
更新:我可以从coverback
的回答中解决一些问题。静止单元格布局不正确。我正在为单元格中每个 UI 对象的约束添加照片。
用户名:
时间戳:
聊天消息:
气泡图:
单元格布局:
cellForRowAtIndexPath:
中的单元格高度始终为 100,即使我从 heightForRowAtIndexPath:
方法返回不同的值。情节提要中的单元格高度为 100。
第三个单元格中的聊天消息从底部被剪掉。
时间戳和聊天消息标签有时没有正确对齐,即使两者都有约束vertical spacing from username label
。
第三个单元格中的用户名标签消失了。
你发现约束有什么问题吗?你可以问我分析约束是否困难。
【问题讨论】:
cell.textString.frame 不工作,更改 chatCell 类中的 cell.textString 帧 请更新代码,因为它没有框架,如你所说。 【参考方案1】:结合thandasoru和coverback的答案解决了我的问题。下面是我使用的代码。
我在自定义UITableViewCell
的类中添加了以下方法。
- (void)layoutSubviews
[super layoutSubviews];
CGFloat maxTextWidth = [UIScreen mainScreen].bounds.size.width * 0.40;
self.userLabel.preferredMaxLayoutWidth = maxTextWidth;
self.chatMessage.preferredMaxLayoutWidth = maxTextWidth;
self.timeLabel.preferredMaxLayoutWidth = self.timeLabel.frame.size.width;
[super layoutSubviews];
UITableView 数据源方法:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
CustomCell * cell = (CustomCell *)[tableView dequeueReusableCellWithIdentifier:@"customCellId"];
// Set all label's text and image to ImageView
...
// Update layout
[cell setNeedsLayout];
[cell layoutIfNeeded];
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
customCell * cell = (customCell *)[self tableView:tableView cellForRowAtIndexPath:indexPath];
NSString * userName = cell.userLabel.text;
NSString * chatText = cell.chatMessage.text;
// Get bounding rect of userName label
CGRect userNameFrame = [userName boundingRectWithSize:CGSizeMake(maxLabelWidth, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:@NSFontAttributeName:cell.userLabel.font context:nil];
// Get bounding rect of chatMessage label
CGRect chatTextFrame = [chatText boundingRectWithSize:CGSizeMake(maxLabelWidth, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:@NSFontAttributeName:cell.chatMessage.font context:nil];
// Calculate cell height from its contents
height = userNameFrame.size.height + chatTextFrame.size.height + PADDING_ABOVE_TOP_LABEL + DISTANCE_BETWEEN_TWO_LABELS + PADDING_BELOW_BOTTOM_LABEL;
return height;
【讨论】:
【参考方案2】:您可以动态确定单元格高度,以便文本显示在一行上。我给了 CGSize(320,568) 作为界限。但是您可以根据需要更改大小
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
NSString *chatText = [[chatData objectAtIndex:row] objectForKey:TEXT];
CGRect frame = [chatText boundingRectWithSize:CGSizeMake(320,568) options:NSStringDrawingUsesLineFragmentOrigin attributes:@NSFontAttributeName:[UIFont systemFontOfSize:18.0f] context:nil];
return frame.height; //returns cell's height after calculating the area that text needs
【讨论】:
我不希望文本出现在单行上。我希望它最多使用屏幕宽度的 60%。然后下一个字符可以转到下一行。 我认为你可以在 CGSizeMake 中改变它【参考方案3】:您正在设置文本的框架并调用sizeToFit
:
CGSize size = [cell.textString.text sizeWithFont:cell.textString.font constrainedToSize:CGSizeMake(SET_WIDTH, MAXFLOAT) lineBreakMode:NSLineBreakByCharWrapping];
cell.textString.frame = ...;
[cell.textString sizeToFit];
这不适用于自动布局。您需要完全删除设置框架和sizeToFit
,其他所有直接设置的框架也是如此。如果在那之后事情不起作用,则意味着某些约束不正确。但是混合方法总是会破坏布局。
对于UILabel
s,请务必将preferredMaxLayoutWidth
设置为标签的宽度,否则文本可能无法正确换行:
- (void)layoutSubviews
[super layoutSubviews];
self.label.preferredMaxLayoutWidth = self.label.frame.size.width;
[super layoutSubviews];
另外,你的高度计算方法不应该和cellForRowAtIndexPath:
做同样的事情,如果你想使用相同的代码,只需调用其他方法来获取一个单元格。
【讨论】:
感谢您的建议。这些很有帮助。它帮助我解决了一些问题。混蛋问题已解决,但单元布局不完美。我认为问题可能会受到限制。我将更新问题以显示每个 UI 对象的约束。以上是关于UITableView 单元格内容未正确显示的主要内容,如果未能解决你的问题,请参考以下文章