以下のコードでは、これらの4つのメソッドがレイアウト推論のために呼び出されています。しかし、なぜそれらすべてが必要なのか、そしてそれらが互いに異なることをするのか、私は少し混乱しています。これらは、自動レイアウトを使用してセルの高さを動的にするプロセスで使用されます。 ( このリポジトリ から この質問 から取得。)
[cell setNeedsUpdateConstraints];
[cell updateConstraintsIfNeeded];
[cell.contentView setNeedsLayout];
[cell.contentView layoutIfNeeded];
そして、それはセルの高さのこのコードブロックからのものです:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
RJTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
[cell updateFonts];
NSDictionary *dataSourceItem = [self.model.dataSource objectAtIndex:indexPath.row];
cell.titleLabel.text = [dataSourceItem valueForKey:@"title"];
cell.bodyLabel.text = [dataSourceItem valueForKey:@"body"];
cell.bodyLabel.preferredMaxLayoutWidth = tableView.bounds.size.width - (kLabelHorizontalInsets * 2.0f);
[cell setNeedsUpdateConstraints];
[cell updateConstraintsIfNeeded];
[cell.contentView setNeedsLayout];
[cell.contentView layoutIfNeeded];
CGFloat height = [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;
return height;
}
しかし、彼らは何が違うのでしょうか?なぜそれらすべてが必要なのですか?
ビューロジックをUIView
サブクラスにカプセル化し、それをSomeView
と呼びます。つまり、SomeView
は、それ自体をlayoutする方法、つまり、その中に他のビューを配置する方法を知っている必要があります(なしで自分自身を描画するビューを作成することもできます)サブビューを使用しますが、それは平均的な開発者のニーズを超えています)。
このレイアウトは[SomeView layoutSubviews]
によって行われます。それをオーバーライドするオプションがあります:
subview.frame = CGRectMake(100 + shiftX, 50 + shiftY, 250 + shiftX - paddingRight, ...
// Oh no, I think I didn't do it right.
しかし、そうする必要はめったにありません。 Cocoa Touchの暗黒時代には、この手動レイアウトが普及していましたが、今では99%のレイアウトを自動レイアウトでカバーできると思います。
システムは、いつ[UIView layoutSubviews]
を呼び出す必要があるかを知る必要があります。初めてビューを描画する必要があるときに明らかに実行されますが、スーパービューフレームが変更されるたびに呼び出されることもあります。 詳細な説明はこちら 。
したがって、システムはしばしば[view layoutIfNeeded]
を呼び出します。 あなたはいつでも呼び出すことができますが、これは[view setNeedsLayout]
を呼び出したイベントがある場合、または手動で呼び出した場合にのみ効果があります。この場合。
Auto Layout( ドキュメント でこのように大文字になっています)は、[SomeView layoutSubviews]
を離れているため、そのように呼び出されますUIView
から継承され、代わりに制約の観点からサブビューの位置を記述します。
自動レイアウトを使用する場合、システムは各レイアウトパスで[view updateConstraintsIfNeeded]
への呼び出しを実行します。ただし、フラグ[view setNeedsUpdateConstraints];
が設定されている場合にのみ、メソッドは-updateConstraints
(実際のジョブを実行します)を呼び出します。
自動レイアウトを使用しない場合、これらの方法は関係ありません。
この例では のように実装できます。
-layoutIfNeeded
と-updateConstraintsIfNeeded
を直接呼び出す必要はめったにありません。これは、UIエンジンが各レイアウトパスで自動的に呼び出すためです。ただし、この場合、作成者はすぐにそれらを呼び出すことを選択しました。これは、結果として得られる高さが、将来のある時点ではなく、現在必要であるためです。
セルの高さを更新するこの方法は正しいようです。 cell
は新しく作成されたセルである可能性があるため、ビュー階層にはまだ追加されていないことに注意してください。これは、それ自体をレイアウトする機能には影響しません。
カスタムビューで、最も「ユニバーサル」から「最もカスタマイズされた」まで、次のオプションを選択します。
-updateConstraints
をオーバーライドします。-layoutSubviews
をオーバーライドします。ビューの制約を変更する可能性のあるものを変更するコードで、
[view setNeedsUpdateConstraints];
すぐに結果が必要な場合は、
[view updateConstraintsIfNeeded];
コードがビューのフレーム使用を変更する場合
[view setNeedsLayout];
最後に、すぐに結果が必要な場合は、
[view layoutIfNeeded];
この場合、4つの呼び出しすべてが必要になるのはこのためです。
記事の詳細な説明をご覧ください Advanced Auto Layout Toolbox、objc.io issue#3