web-dev-qa-db-ja.com

UITableViewCellでのUILabel幅の動的計算

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;
   }
23
Leonard

フォントを明示的に設定すると、問題が解決します。

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

Gory Detals:
テーブルビューが最初に読み込まれるとき、フォントサイズが0であるため、このスニペットはゼロ幅を返します。

[textLabel.text sizeWithFont:textLabel.font]

セルフォントのポイントサイズを表示することでこれを理解しました。

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

あなたが説明したように、セルが画面から消えて戻ってくるまで、ポイントサイズはゼロでした。

16
bentford

私はそれがバグであるべきであるということは十分に迷惑であることに完全に同意します。 AppleのNiceの人々が、セルが完全にセットアップされていることを確認せずにセルの高さを要求するのはなぜですか。愚かな!ただし、非推奨の関数を使用する代わりに、次のことを試してください。

[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;
}
5
SpareTime

同じ問題が見つかりましたが、回避策が見つかりました。参考までに、Apple(Bug ID#7535066)でバグを発生させました。Lex、あなたの例では、textLabel.fontの代わりにcell.fontを使用すると、機能するはずですが、機能します。これは非推奨のメソッド呼び出しであるため、コンパイラの警告が表示されます。発生したバグの詳細を確認できるかどうかわからないため、ここに詳細を貼り付けます。

iPhone SDK 3.1.2(7D11)NSString UIKitAdditionsメソッドsizeWithFontはnilを返します

まとめUITableViewデリゲートメソッドでUITableViewCellsを装飾しています。

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

新しいビューを正しくフォーマットするために、すでにセルにあるテキストの長さを見つけたいので、NSString UIKitAdditionsメソッドを呼び出しています。

  • (CGSize)sizeWithFont:(UIFont *)fontconstraintToSize:(CGSize)size

Font引数にcell.textLabel.fontを使用すると、常に空のCGSizeが返されます。

引数にDEPRECATEDメソッドcell.fontを使用すると、期待どおりにCGSize値が返されます。

再現手順1.TableViewを使用してUITableViewControllerを作成し、サンプルデータを入力します。2。スタブメソッドcellForRowAtIndexPathで、コメントの後に//セルを設定し、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

回避策と分離:

前述のように、非推奨のメソッドを使用してフォントを取得します。しかし、それは見知らぬ人になります!

上記の2つの方法を逆にします。

 
 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]が正しく機能するようになります。

3
Gene Myers

[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);
3
ArunGJ