从 Nib 加载的 UITableViewCell 中的 UILabel 大小调整

Posted

技术标签:

【中文标题】从 Nib 加载的 UITableViewCell 中的 UILabel 大小调整【英文标题】:UILabel size adjustment within a UITableViewCell loaded from Nib 【发布时间】:2013-09-22 23:50:07 【问题描述】:

在一个 Cell 中的 UILabel 包含一个 NSLocalizedString;根据语言的不同,从几个字符到一个段落不等。 UILabel 的框架有时会,有时不会绘制以适应字符串长度。我认为这是重用的问题,但我不知道如何解决它。

我在viewDidLoad 中从 Nibs(项目要求)加载了一系列五个不同的 UITableViewCell 子类:

UINib *Cell1Nib = [UINib nibWithNibName:@"customCell1" bundle:nil];
[[self tableView] registerNib:Cell1Nib forCellReuseIdentifier:@"custCell1"];

UINib *Cell2Nib = [UINib nibWithNibName:@"customCell2" bundle:nil];
[[self tableView] registerNib:Cell2Nib forCellReuseIdentifier:@"custCell2"];
//etc.

我有一个助手可以根据使用的文本获取 UILabel 的高度:

- (CGFloat)getTextHeight:(NSString *)locStr forLabelWidth:(CGFloat)w 
    UILabel  *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, w, 110)];
    label.numberOfLines=0;
    label.lineBreakMode=NSLineBreakByCharWrapping;
    label.text = locStr; // highly variable & already localized
    label.font = [UIFont preferredFontForTextStyle:UIFontTextStyleBody]; 
    CGSize maxSize = CGSizeMake(w, CGFLOAT_MAX);
    CGSize requiredSize = [label sizeThatFits:maxSize];
    label = nil; // ARC paranoia
    return requiredSize.height;

heightForRowAtIndexPath 中,我调用getTextHeight:forLabelWidth:,使用它来确定单元格高度并将结果存储到一个名为labelHeightforRow. 的NSMutableArray 中。到目前为止,一切正常。

我这样创建表:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
    UITableViewCell *cell = nil;
    DLX_CellDescriptor *desc = [[DLX_CellDescriptor alloc] initWithRow:indexPath.row];
    //DLX_CellDescriptor describes attributes for cell at index , essentially a list of strings
    CGFloat helpTextHeight = [[labelHeightforRow objectAtIndex:indexPath.row] floatValue];

    if ([desc.nibToUse caseInsensitiveCompare:@"custCell1"] == NSOrderedSame ) 
        DLX_CustCell1 *currCell = (DLX_CustCell1 *)[self.tableView dequeueReusableCellWithIdentifier:@"custCell1"];
        CGPoint origin = currCell.theLabel.frame.origin;
        CGFloat w = currCell.theLabel.frame.size.width;
        currCell.theLabel.frame = CGRectMake(origin.x, origin.y, w, helpTextHeight);
        currCell.theLabel.text = desc.localizedText;
        currCell.theLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleBody];
        currCell.tag = indexPath.row;
        cell = currCell;
     else if ([desc.nibToUse caseInsensitiveCompare:@"custCell2"] == NSOrderedSame ) 
        DLX_CustCell2 *currCell = (DLX_CustCell2 *)[self.tableView dequeueReusableCellWithIdentifier:@"custCell2"];
        CGPoint origin = currCell.theLabel.frame.origin;
        CGFloat w = currCell.theLabel.frame.size.width;
        currCell.theLabel.frame = CGRectMake(origin.x, origin.y, w, helpTextHeight);
        currCell.theLabel.text = desc.localizedText;
        currCell.theLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleBody];
        currCell.tag = indexPath.row;
        cell = currCell;
     // for about 26 rows of 5 different non-identical sytles
      // simplified in this example
    return cell;

这个问题是在创建初始TableView时,UILabel是Nib中指定的高度:截断超长文本并在下面给出大的空白(来自正确的单元格高度调整)。重绘表格时,UILabel 变为代码中指定的正确高度;显示整个字符串。然后,如果重新创建单元格;比如说,在它滚出屏幕并绘制了另一个单元格类型之后,长文本标签再次使用从笔尖截断的高度。

我尝试将layoutSubviews 放入自定义 UITableViewCell(例如 customCell1.m)中:

- (void)layoutSubviews 
    NSInteger currCell = self.tag;
    DLX_CellDescriptor *desc = [[DLX_CellDescriptor alloc] initWithRow:currCell];
    CGPoint origin = theLabel.frame.origin;
    CGSize size = theLabel.frame.size;
    CGFloat textHeight = [self getTextHeight:desc.localizedText forLabelWidth:size.width];
    theLabel.frame = CGRectMake(origin.x, origin.y, size.width, textHeight);
    [super layoutSubviews];

但这具有不变地确保使用笔尖高度的效果;即使经过检查,textheight 是正确的(而且,对于某些语言,比 Nib 的高度大得多。)

【问题讨论】:

【参考方案1】:

由于您的单元格相对简单,因此解决问题的一种简单方法是不要重复使用。只需从包中加载 nib 文件。删除那些registerNib相关的代码。并这样做:

NSString *reuseIdentifier = @"DistrictCellReuseIdentifier";
DistrictCell *cell = [tableView dequeueReusableCellWithIdentifier:reuseIdentifier];
if (cell == nil) 
    cell = [[NSBundle mainBundle] loadNibNamed:@"DistrictCell" owner:self options:nil][0];

【讨论】:

我大大简化了我在问题中提供的示例代码,以免使问题变得混乱。实际的单元格有 UIControls、图像、背景、手风琴功能等。但是,我不熟悉关闭重用。能详细点吗? 建议的代码,如果按类型实现,会导致以不同的方式获得相同的错误。但是,它确实为我指明了正确的道路。我认为解决重用问题的方法是确保重用标识符是唯一的,例如 NSString *reuseIdentifier = [NSString stringWithFormat:@"CellReuseIdentifier%d",indexPath.row]; @NSConfusedCoder 哦,对不起,我忘记了 NO 重用!是的,你的方法是正确的。

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

从 nib 加载 UITableViewCell 子类时给出的类型错误

从 xib 加载 UITableViewCell 会导致加载 nib 但未设置视图出口

从 Nib 加载的 UITableViewCell 中的 UILabel 大小调整

从 NIB 加载自定义 UITableViewCell 问题

将自定义 UITableViewCell 从 nib 加载到 Swift 中的 UIViewController

如何使用 Swift 从 UITableViewCell 内的 NIB 调整自定义 UIView 的大小?