在 UITableViewCell 中自动调整 UILabel 的大小

Posted

技术标签:

【中文标题】在 UITableViewCell 中自动调整 UILabel 的大小【英文标题】:Autoresizing of UILabels in a UITableViewCell 【发布时间】:2011-02-23 15:00:53 【问题描述】:

我将自己的UILabels 添加到UITableViewCellcontentView 中,因为我需要对布局进行比默认 UITableViewCellStyles 提供的更多控制。本质上,我希望 detailLabel 优先于 textLabel,因此 textLabel 会被截断。

我的UITableViewController 中有以下代码:

- (UITableViewCell *)tableView:(UITableView *)tableView
  cellForRowAtIndexPath:(NSIndexPath *)indexPath

  static NSString * const kCellIdentifier = @"CustomCell";

  UITableViewCell * cell =
      [tableView dequeueReusableCellWithIdentifier:kCellIdentifier];

  UILabel * titleLabel, * dateLabel;

  if(cell == nil)
  
    cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
        reuseIdentifier:kCellIdentifier] autorelease];

    cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;

    titleLabel = [[[UILabel alloc] init] autorelease];
    titleLabel.tag = kTitleLabelTag;
    titleLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth;

    dateLabel = [[[UILabel alloc] init] autorelease];
    dateLabel.tag = kDateLabelTag;
    dateLabel.textColor = [UIColor blueColor];
    dateLabel.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin;

    [cell.contentView addSubview:titleLabel];
    [cell.contentView addSubview:dateLabel];
  

  [self configureCell:cell atIndexPath:indexPath];
  return cell;


- (void)configureCell:(UITableViewCell *)pCell
  atIndexPath:(NSIndexPath *)pIndexPath

  const float kHeight = 44.0, kLeftIndent = 8.0, kOverallWidth = 293.0,
      kGap = 1.0;

  UILabel * titleLabel, * dateLabel;
  titleLabel = (UILabel *)[pCell.contentView viewWithTag:kTitleLabelTag];
  dateLabel = (UILabel *)[pCell.contentView viewWithTag:kDateLabelTag];

  NSString * dateText = @"9:39 AM";

  // Calculate the size of dateLabel
  CGSize dateSize = [dateText sizeWithFont:[dateLabel font]
      constrainedToSize:CGSizeMake(kOverallWidth, kHeight)];

  const float dateXPos = kOverallWidth - dateSize.width;
  dateLabel.frame = CGRectMake(dateXPos, 0.0, dateSize.width, kHeight);
  titleLabel.frame = CGRectMake(kLeftIndent, 0.0,
      dateXPos - kLeftIndent - kGap, kHeight);

  titleLabel.text = @"Some potentially very long text which will be wrapped.";
  dateLabel.text = dateText;
  pCell.contentView.backgroundColor = [UIColor purpleColor];

上面的代码产生了错误的结果。最初显示表格视图时,它看起来像 this image of the renderings 中的图 1)。

所以在所有dateLabels 的右侧有一个不需要的空白。 (紫色背景只是为了更好地了解正在发生的事情)

当像在图像中的 2) 那样向上拖动 tableview 时,它会弹回并看起来像 3)。

第一行现在正好是我想要的布局,它在configureCell:atIndexPath: 中计算。我猜这种行为的发生是因为单元被重新使用然后再次配置。

所以感觉好像我缺少某种初始化,我尝试调用pCellpCell.contentViewsetNeedsLayoutlayoutSubviews,但从未实现初始正确渲染。

只有当我将titleLabeldateLabelautoresizingMask 设置为UIViewAutoresizingNone 时,我才能得到正确的初始渲染,但是滑动删除不起作用,因为删除按钮在dateLabel 上渲染.

我必须在我的代码中进行哪些更改,以使所有单元格最初呈现就像第三张图片中的第一个单元格一样?

谢谢!

PS:我想内联图片,但不幸的是我没有足够的声誉。

【问题讨论】:

+1 用于使用 const float 而不是 #define 以获得更好的类型安全性。我知道在 Apple 的示例代码中他们经常使用预编译器指令,但使用 consts 更好。恕我直言 【参考方案1】:

一个好的,也许更简单的方法是:

首先创建一个自定义 UITableViewCell 子类,您可以使用 Interface Builder 进行设置。如果“MyTableViewCell”是您的自定义单元格视图,您可以像这样在 CellForRowAtIndexPath 中初始化它:

MyTableViewCellClass *cell = (MyTableViewCellClass *)[tableView dequeueReusableCellWithIdentifier:@"MyTableViewCellClass"] autorelease];

if (!cell)
cell = [[[MyTableViewCellClass alloc] initWithStyle:UITableViewCellStyleDefault   reuseIdentifier:@"MyTableViewCellClass"] autorelease];

// Call specific methods on your cell to pass information to it, not for display
[cell setProperties:...];

然后在你的自定义 UITableViewCell 子类中实现 layoutSubviews 方法。例如:

-(void) layoutSubviews

// You must call this first to make sure your cell gets current parent information
[super layoutSubviews];

// Retrieve the content view bounds. This will include the edit symbols when present (delete button and ordering symbol
float inset = 5.0;
CGRect bounds = [[self contentView] bounds];

// Keep on going here with your own view layout.


这样做您基本上将单元模型 (CellForRowAtIndexPath) 与单元视图(您的单元绘图的自定义实现)分开。如果您稍后更改单元格的实现(布局),您只需更改单元格布局即可轻松完成此操作,而无需担心 CellForRowAtIndexPath 方法。

【讨论】:

谢谢!在子类的layoutSubviews 方法中从configureCell: 执行代码,然后使用bounds.size.width 而不是我固定的kOverallWidth 解决了它。 @Torsten 很高兴它有帮助。祝你的应用好运。【参考方案2】:

如果您使用 storyboard ,您应该在文件检查器中禁用“使用自动布局”!

然后设置单元格的属性autoresizesSubviews

- (void)awakeFromNib

    // Initialization code
    self.autoresizesSubviews=YES;


最后一步是配置 Label 的框架,覆盖 UITableViewCell 类的 layoutSubviews 方法

-(void)layoutSubviews

    [super layoutSubviews];
    CGFloat top=VerticalPadding;
    CGFloat left=HorizentalPadding;
    CGFloat width=CGRectGetWidth(self.frame)-2*HorizentalPadding;
    CGFloat height=CGRectGetHeight(self.frame)-2*VerticalPadding;
    CGRect rect=CGRectMake(left, top, width, height);
    self.Label.frame=rect;


【讨论】:

以上是关于在 UITableViewCell 中自动调整 UILabel 的大小的主要内容,如果未能解决你的问题,请参考以下文章

在 UITableViewCell 中自动调整 UILabel 的大小

在具有自动布局的 UITableViewCell 中动态调整大小的 UIWebView - 违反约束

让 UITableViewCell 使用自动布局调整自身大小

UITableViewCell 自动调整高度不起作用

自动调整子类 UITableViewCell 子视图的大小

以自定义样式 UITableViewCell 自动调整 UILabel