9

まとめ

セルのフレームまたはそのコンテンツビューがどのようになるか(編集、回転、アクセサリビューなどのため)が常にわからないtableView:heightForRowAtIndexPath:場合、セルに高さを計算するための最良の方法は何ですか?可変高さのテキストフィールドまたはラベル?

私の1つにはUITableViewController's、次のプレゼンテーションが含まれています:UITextViewを使用したUITableViewCell。

UITextViewは、UITableViewCellと同じ幅と高さである必要があります。

ここに画像の説明を入力してください

UITableViewCellサブクラスを作成し、それをUITextViewで初期化しました(UITextViewはUITableViewControllerのプライベートフィールドです)

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ 
     static NSString *CellIdentifier = @"TextViewCell";
     UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
     if (cell == nil) {
         cell = [[[BTExpandableTextViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier textView:_notesTextView] autorelease];
     }    
     return cell;
}

UITableViewCellサブクラスに次のメソッドを実装しました。

- (void)layoutSubviews{
    [super layoutSubviews];
    CGFloat height = [textView.text sizeWithFont:textView.font constrainedToSize:CGSizeMake(textView.frame.size.width, MAXFLOAT)].height + textView.font.lineHeight;
    textView.frame = CGRectMake(0, 0, self.contentView.frame.size.width, (height < textView.font.lineHeight * 4) ? textView.font.lineHeight * 4 : height);    
    [self.contentView addSubview:textView];
}

そしてもちろん、私は次のUITableViewDataSourceメソッドを実装しました(見てください!私はself.view.frame.size.widthを使用しています(しかし実際にはUITableViewCell contentViewフレーム幅が必要です):

- (CGFloat)tableView:(UITableView*)tableView heightForRowAtIndexPath:(NSIndexPath*)indexPath{

    CGFloat height  = [_notesTextView.text sizeWithFont:_notesTextView.font 
                                      constrainedToSize:CGSizeMake(self.view.frame.size.width, MAXFLOAT)].height;        
    CGFloat groupedCellCap = 20.0;     
    height          += groupedCellCap; 

    if(height < [BTExpandableTextViewCell minimumTextViewHeightWithFont:_notesTextView.font]){
        height = [BTExpandableTextViewCell minimumTextViewHeightWithFont:_notesTextView.font];
    }        
    return height;
}    

また、次のメソッドを実装しました(これはそれほど重要ではありませんが、とにかく投稿しません。セルの高さが動的であることを説明するために、UITextViewでテキストを変更すると縮小または拡大します)

 - (void)textViewDidChange:(UITextView *)textView{
    CGFloat height = [_notesTextView.text sizeWithFont:_notesTextView.font 
                                 constrainedToSize:CGSizeMake(_notesTextView.frame.size.width, MAXFLOAT)].height;
    if(height > _notesTextView.frame.size.height){
        [self.tableView beginUpdates];
        [self.tableView endUpdates];
    }
}

そして今、私の質問は次のとおりです。 ビューをロードした後、UITableViewControllerは次の順序でメソッドを呼び出しています:(簡略化のためにtitleForHeaderInSectionなどの一部を削除します)

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
- (CGFloat)tableView:(UITableView*)tableView heightForRowAtIndexPath:(NSIndexPath*)indexPath{ 

そしてその時だけ

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

見て!cellForRowAtIndexPathの前に正しいUITableViewCellの高さを返す必要があります!つまり、UITableViewCellcontentViewフレームがわかりません。そして、私はそれをプログラムで取得することはできません。

この幅は、次のいずれかになります。

  1. iPhoneプレーンテーブル、縦向き
  2. iPhoneプレーンテーブル、横向き
  3. iPhoneグループテーブル、縦向き
  4. iPhoneグループテーブル、横向き
  5. iPadでも同じです(別の4つの値)

また、UITableViewCellのaccessoryTypeのため、またはUITableViewの編集状態のために、contentViewフレームが小さくなる可能性があることを忘れないでください。(たとえば、任意の編集状態および任意のaccessoryViewで任意の高さの複数行UILabelを持つUITableViewCellがある場合)

したがって、この問題は根本的なものです。セルレイアウトcontentViewの前にこの高さを返す必要があるため、制約のためにセルcontentViewフレーム幅を取得できません。(ちなみに、これはかなり論理的です)しかし、このcontentViewフレームは本当に重要です。

もちろん、この幅を正確に把握して「ハードコード」できる場合もあります(たとえば、UITableViewCellAccessoryDisclosureIndicatorの幅は20ピクセルで、tableViewを編集状態にできない場合は、self.view.frame.size.width-20とタスクを記述できます。終わらせる)!または、contentViewがUITableViewControllerのビューフレームと等しい場合もあります。

-tableView:heightForRowAtIndexPath:メソッドでself.view.frame.widthを使用していることがあります(今のように、かなりうまく機能しますが、グループ化されたUITableViewのために完全ではありませんが、いくつかの定数値を減算する必要があります。 2つのデバイス*2つの向き)

UITableViewCellにいくつかの#defined定数がある場合があります(幅が正確にわかっている場合)...

ダミーの事前に割り当てられたUITableViewCellを使用している場合があります(これはばかげていますが、非常にエレガントで使いやすい場合もあります)...

しかし、私はそれの何も好きではありません。

最良の決定は何ですか? たぶん、アクセサリビュー、デバイスの向き、デバイスタイプ、テーブルビューの編集状態、テーブルビューのスタイル(プレーン、グループ化)、コントローラービューフレームなどのパラメーターで初期化されるヘルパークラスを作成する必要があります。いくつかの定数(グループ化されたtableViewオフセットなど)を使用して、予想されるUITableViewCell contentView幅を見つけますか?;)

ありがとう

4

2 に答える 2

1

テーブル ビューは、メソッドを使用して、セルtableView:heightForRowAtIndexPath:を作成する前に contentSize を決定します。UITableViewCell立ち止まって考えてみると、これは理にかなっています。a で最初に行うことは、UIScrollViewその contentSize を設定することだからです。以前に同様の問題に遭遇したことがあり、UITableViewCell に入るコンテンツを取得してその高さを予測できるヘルパー関数を用意するのが最善であることがわかりましたUITableViewCell。したがって、テキストを each に格納する何らかのデータ構造を作成する必要があると思いますUITableViewCell. そうすれば、 を参照せずに、必要なテキストの高さを見つけることができますUITableViewCell

于 2012-06-20T09:45:27.630 に答える
1

UITableViewCell サブクラスの「-layoutSubviews」で、テーブル ビュー セルに含まれるラベルの高さを真に動的に計算できますが、「-tableView:heightForRowAtIndexPath:」のセルの高さに対してこれを行う同様の方法 (私が知っている) はありません。テーブル ビュー デリゲートの。

このことを考慮:

- (void)layoutSubviews
{
    [super layoutSubviews];

    CGSize size = [self.textLabel.text sizeWithFont:self.textLabel.font
                                  constrainedToSize:CGSizeMake(self.textLabel.$width, CGFLOAT_MAX)
                                      lineBreakMode:self.textLabel.lineBreakMode];
    self.textLabel.$height = size.height;
}

cell.textLabel.frame残念ながら、'-tableView:heightForRowAtIndexPath:' が呼び出されるまでには、まだ に設定されているため、早すぎCGRectZero = {{0, 0}, {0, 0}}ます。

私の知る限り、コンテンツビューのフレームでも、個々のラベルのフレームを合計しても、これを行うことはできません...

私が考えることができる唯一の方法は、任意のデバイス上の任意のデバイスの向きですべての可能な幅をカバーしようとする便利なクラス、メソッド、定数などを考え出すことです:

@interface UITableView (Additions)

@property (nonatomic, readonly) CGFloat padding;

@end

@implementation UITableView (Additions)

- (CGFloat)padding
{
    if (self.formStyle == PTFormViewStylePlain) {
        return 0;
    }

    if (self.$width < 20.0) {
        return self.$width - 10.0;
    }

    if (self.$width < 400.0 || [[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
        return 10.0;
    }

    return MAX(31.0, MIN(45.0, self.$width * 0.06));
}

@end

また、最近では横向きの新しい iPhone 5 の 4 インチ幅 (480 ではなく 568) もあることに注意してください。

この全体がかなり不安です、私は知っています...乾杯。

于 2012-09-18T07:43:02.373 に答える