まとめ
セルのフレームまたはそのコンテンツビューがどのようになるか(編集、回転、アクセサリビューなどのため)が常にわからない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フレームがわかりません。そして、私はそれをプログラムで取得することはできません。
この幅は、次のいずれかになります。
- iPhoneプレーンテーブル、縦向き
- iPhoneプレーンテーブル、横向き
- iPhoneグループテーブル、縦向き
- iPhoneグループテーブル、横向き
- 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幅を見つけますか?;)
ありがとう