【问题标题】:dynamic calculation of UILabel width in UITableViewCellUITableViewCell中UILabel宽度的动态计算
【发布时间】:2009-12-22 17:36:55
【问题描述】:

我正在构建一个基于 UITableViewCellStyle1(左右)的自定义应用程序内设置视图。

我正在尝试动态计算单元格左侧标签(标题)的宽度,以确定右侧文本字段的宽度。

当我在模拟器中启动应用程序并加载视图时,标题标签的宽度为零,直到我向下滚动视图并且看不到单元格,然后当我向上滚动时,大小会按预期调整。我相信这可能与细胞重复使用有关。

我需要单元格中的标题标签在视图加载时具有正确的宽度,而不是在它们消失一次之后。

- (UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath
  {
      static NSString* reuseIdentifier = @"SettingsCell";

UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:reuseIdentifier];

if ( !cell )
{   
    cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:reuseIdentifier] autorelease];
    [cell setBackgroundColor:[UIColor baeDarkGrayColor]];


    UILabel* cellLabel = [cell textLabel];
    [cellLabel setTextColor:[UIColor whiteColor]];
    [cellLabel setBackgroundColor:[UIColor clearColor]];

    [cell setUserInteractionEnabled:YES];
    [cell setSelectionStyle:UITableViewCellSelectionStyleGray];
}

// Populate cell with corresponding data.
NSDictionary* tableSection = [_tableData objectAtIndex:indexPath.section];

// Set the label
UILabel* textLabel = [cell textLabel];
NSString* labelString = [[tableSection objectForKey:@"itemTitles"] objectAtIndex:indexPath.row];
[textLabel setText:labelString];

   //   CGSize constrainedSize;
  //    constrainedSize.width = MAXFLOAT;
 // constrainedSize.height = MAXFLOAT;

CGSize textLabelSize = [textLabel.text sizeWithFont:textLabel.font /*constrainedToSize:constrainedSize*/];

NSLog(@"text label width: %f", textLabelSize.width);    


// Set the accessory view
BAESettingsTableCellAccessoryType accessoryType = [[[tableSection objectForKey:@"itemAccessories"] objectAtIndex:indexPath.row] integerValue];
switch ( accessoryType )
{
    case BAESettingsTableCellAccessoryDisclosureIndicator:
    {
        UIImageView* disclosureView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"AccessoryDisclosure.png"]];
        [cell setAccessoryView:disclosureView];
        [disclosureView release];
        break;
    }
    case BAESettingsTableCellAccessoryOnOffSwitch:
    {
        UISwitch* onOffSwitch = [[UISwitch alloc] initWithFrame:CGRectZero];
        [onOffSwitch setOn:YES];
        [cell setAccessoryView:onOffSwitch];
        [onOffSwitch release];
        break;
    }
    case BAESettingsTableCellAccessoryNone:
        // default:
        // break;
    {

        CGRect cellFrame = [cell frame];

        float detailTextFieldWidth = cellFrame.size.width - ( textLabelSize.width + 50 );
        float detailTextFieldHeight = cellFrame.size.height - 1;

        NSLog(@"detail text field calculated frame width, height, %f, %f", detailTextFieldWidth, detailTextFieldHeight);


        CGRect frame = CGRectMake(cellFrame.origin.x, cellFrame.origin.y, detailTextFieldWidth, detailTextFieldHeight);


        UITextField* textField = [[UITextField alloc] initWithFrame:frame];
        NSString* detailLabelString = [[tableSection objectForKey:@"itemDetailStrings"] objectAtIndex:indexPath.row];
        textField.text = detailLabelString;
        textField.textColor = cell.detailTextLabel.textColor;
        textField.textAlignment = UITextAlignmentRight;
        textField.borderStyle = UITextBorderStyleRoundedRect;
        [cell setAccessoryView:textField];
        [textField release];
        break;
    }

}

return cell;
   }

【问题讨论】:

    标签: iphone uitableview dynamic uilabel


    【解决方案1】:

    显式设置字体可以解决您的问题。

    CGSize textLabelSize = [textLabel.text sizeWithFont:[UIFont systemFontOfSize:17]];
    

    血腥细节:
    当 tableview 首次加载时,由于字体大小为 0,此 sn-p 返回零宽度。

    [textLabel.text sizeWithFont:textLabel.font]
    

    我通过显示单元格字体的磅值来解决这个问题。

    NSLog(@"font size: %f", cell.textLabel.font.pointSize);
    

    点大小为零,直到单元格离开屏幕并返回,正如您所描述的那样。

    【讨论】:

      【解决方案2】:

      我完全同意它应该是一个错误已经足够烦人了。为什么苹果公司的好人会在不确保电池完全设置的情况下要求电池高度。愚蠢的!但是,不要使用已弃用的函数,请尝试:

      [cell layoutIfNeeded];
      

      调用此方法与正在设置的单元格具有相同的效果,包括边界、单元格字体等。因此,此后的任何计算都可以访问完全设置的单元格。这是整个代码:

      -(CGFloat) tableView:(UITableView *) tableView heightForRowAtIndexPath:(NSIndexPath *) indexPath {
      
        // Find the cell for this index path
        UITableViewCell *cell = [self tableView:tableView cellForRowAtIndexPath:indexPath];
        CGFloat cellHeight = cell.frame.size.height;
      
        // Calculate text size after forcing a layout
        [cell layoutIfNeeded];
        CGSize textSize = [cell.textLabel.text sizeWithFont:cell.textLabel.font constrainedToSize:CGSizeMake(cell.contentView.bounds.size.width, 99999) lineBreakMode:cell.textLabel.lineBreakMode];
      
        // Only change the cell height if the text forces a growth
        if (textSize.height > cellHeight) {
          cellHeight = textSize.height;
        }
      
        return cellHeight;
      }
      

      【讨论】:

      • 创意十足。 [单元格布局如果需要];效果很好!其他解决方案不起作用。非常感谢!
      【解决方案3】:

      我发现了同样的问题,但我找到了解决方法。仅供参考,我已经向 Apple 提出了一个错误(错误 ID# 7535066)。 Lex,在您的示例中,如果您使用 cell.font 而不是 textLabel.font,它应该可以工作,尽管您会收到编译器警告,因为这是一个已弃用的方法调用。我不确定您是否能够看到我提出的错误的详细信息,所以我将详细信息粘贴在这里:

      iPhone SDK 3.1.2 (7D11) NSString UIKit Additions 方法 sizeWithFont 返回 nil

      总结 我在 UITableView 委托方法中装饰 UITableViewCells:

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

      我希望找到单元格中已有文本的长度,以正确格式化新视图,因此我调用了 NSString UIKit Additions 方法:

      • (CGSize)sizeWithFont:(UIFont *)font constrainedToSize:(CGSize)size

      当我使用 cell.textLabel.font 作为字体参数时,它总是返回一个空的 CGSize

      如果我使用已弃用的方法 cell.font 作为参数,它确实会按预期返回 CGSize 值。

      复制步骤 1. 创建一个带有 TableView 的 UITableViewController,并用一些示例数据填充它 2. 在存根方法 cellForRowAtIndexPath 中,在注释 //Set up the cell 之后,在 cell.textLabel.text 被填充的地方,放入以下内容:

        
       CGSize size = [cell.textLabel.text sizeWithFont:[[cell textLabel] font] constrainedToSize:CGSizeMake(320, 480)];
       NSLog(@"cell frame: %f %f", size.width, size.height);
      
       CGSize size2 = [cell.textLabel.text sizeWithFont:[cell font] constrainedToSize:CGSizeMake(320, 480)];
       NSLog(@"DEPRECATED cell frame: %f %f", size2.width, size2.height);
      
      

      预期结果

      如果有的话,您会期望使用 Deprecated 方法检索字体、失败或至少两者都返回相同结果的调用。

      实际结果:

      2010-01-12 22:06:36.645 PrefTest[9659:207] 单元格框架:0.000000 0.000000 2010-01-12 22:06:36.646 PrefTest[9659:207] 已弃用的单元格框架:88.000000 24.000000

      解决方法和隔离:

      如前所述,使用不推荐使用的方法来获取字体。但它变得陌生!

      把我上面给的两个方法反过来:

       
       CGSize size2 = [cell.textLabel.text sizeWithFont:[cell font] constrainedToSize:CGSizeMake(320, 480)];
       NSLog(@"DEPRECATED cell frame: %f %f", size2.width, size2.height);
      
          CGSize size = [cell.textLabel.text sizeWithFont:[[cell textLabel] font] constrainedToSize:CGSizeMake(320, 480)];
       NSLog(@"cell frame: %f %f", size.width, size.height);
      

      现在的结果是:

      2010-01-12 22:06:36.645 PrefTest[9659:207] 单元格框架:88.000000 24.000000 2010-01-12 22:06:36.646 PrefTest[9659:207] 已弃用的单元格框架:88.000000 24.000000

      似乎仅仅引用 [cell font] 就足以强制 [[cell textLabel] font] 正常工作。

      【讨论】:

        【解决方案4】:

        使用 [myLbl sizeToFit]; 自动调整标签大小。

        这里是示例代码。

        UILabel *lbl1, *lbl2;
            if (cell == nil) {
        
           UILabel *lbl1 = [[UILabel alloc] init];
                    [lbl1 setFont:[UIFont boldSystemFontOfSize:20]];
                    [cell.contentView addSubview:lbl1];
                    lbl1.frame = CGRectMake(3, 10, 0, 0);
                    lbl1.tag = 10;
                    [lbl1 release];
        
                UILabel *lbl2 = [[UILabel alloc] init];
                [lbl2 setFont:[UIFont systemFontOfSize:20]];
                [cell.contentView addSubview:lbl2];                 
                lbl2.tag = 20;
                [lbl2 release];
        }
        else {
               lbl1 = (UILabel*)[cell.contentView viewWithTag:10];
               lbl2 = (UILabel*)[cell.contentView viewWithTag:20];
        }
        
          lbl1.text = @"Hello ";
            [lbl1 sizeToFit];
        
        lbl2.text = @"World";
                [lbl2 sizeToFit];
                lbl2.frame = CGRectMake(lbl1.frame.origin.x+lbl1.frame.size.width+5,
                                        lbl1.frame.origin.y,
                                        lbl2.frame.size.width,
                                        lbl1.frame.size.height);
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-11-02
          • 2012-10-18
          • 1970-01-01
          • 2011-01-08
          • 2010-11-03
          • 1970-01-01
          相关资源
          最近更新 更多