UICollectionViewを適切にサイズ変更して、コンテンツを完全に表示するにはどうすればよいですか?フレームの設定、reloadData
の呼び出し、レイアウトの無効化など、多くのことを試しました。
self.collectionView.contentSize = CGSizeMake(300, 2000);
self.collectionView.frame = CGRectMake(0, 0, 300, 2000);
[self.collectionView reloadData];
[self.collectionView.collectionViewLayout invalidateLayout];
しかし、これは効果がありません。ボタンを押した後、次のような初期ビューがまだ表示されます。
100個の要素を生成するデータソースがある小さなデモプログラムがあります。 Interface Builderでは、最初にUICollectionViewのサイズを小さな値に設定してすべての要素が収まらないようにし、その後ボタンを押してから上記のコードを実行します。 UICollectionViewにすべての要素が表示されるはずですが、そうではありません。
編集:デモプログラムは https://github.com/ mjdemilliano/TestUICollectionView 。
EDIT2:ある時点でフレームの更新が失われることがわかりました。再び、現在のフレームは古い値に戻ります。ボタンイベントハンドラーにいくつかのログステートメントを追加すると、ログ出力は次のようになります。
before: frame = {{0, 58}, {320, 331}}, contentSize = {320, 1190}
update button pressed
after: frame = {{0, 0}, {300, 2000}}, contentSize = {300, 2000}
before: frame = {{0, 58}, {320, 331}}, contentSize = {320, 1190}
update button pressed
after: frame = {{0, 0}, {300, 2000}}, contentSize = {300, 2000}
フレームの変更が保持されない理由がわかりません。何が変更されているのですか。
ある時点で、ハードコーディングされた値をフローレイアウトから取得した値に置き換えますが、それを除外し、私の例をできるだけシンプルに保ちたいと思いました。
コンテキスト:最終的にやりたいことは次のとおりです。ラベルや画像などのさまざまなコントロールを備えたスクロール可能なビューと、動的コンテンツを備えたコレクションビューがあります。コレクションビューだけでなく、すべてをスクロールしたいので、コレクションビューの独自のスクロール機能を使用していません。
最終的には、すべての自動レイアウトの問題を修正し、制約を使用してコレクションビューの高さを修正することでこれを解決しました。その後、コンテンツが変更されたことがわかっているときは常に、値collectionView.contentSize.height
を使用して制約の値を更新します。
self.verticalLayoutConstraint.constant = self.collectionView.contentSize.height;
次に、コレクションビューのサイズが適切に変更され、全体的なスクロールビュー内で適切に動作します。 GitHubテストプロジェクトを変更して更新しました。
私にとっては、iOSに「コレクションビューのフレームの高さを必要に応じて大きくする」のではなく、制約を手動で更新することでこれを行うことは適切ではありませんが、私が来た最高の方法ですこれまでのところ。もしあればもっと良い答えを投稿してください。
Swift 3:
override func sizeThatFits(_ size: CGSize) -> CGSize {
if (self.superview != nil) {
self.superview?.layoutIfNeeded()
}
return collectionView.contentSize
}
UICollectionViewFlowLayout *flowLayout;
flowLayout = [[UICollectionViewFlowLayout alloc]init];
[flowLayout setScrollDirection:UICollectionViewScrollDirectionVertical];
[flowLayout setMinimumInteritemSpacing:0.0f];
[flowLayout setMinimumLineSpacing:0.0f];
[self.collectionView setPagingEnabled:NO];
[flowLayout setItemSize:CGSizeMake(322.0, 148.0)]; //important to leave no white space between the images
[self.collectionView setCollectionViewLayout:flowLayout];
ストーリーボードの自動レイアウトはあまり役に立たないことがわかりました。 collectionViewのUICollectionViewFlowLayoutの正しい設定は、実際のヘルプです。 setItemSizeを使用してアイテムのサイズを調整すると、希望する結果が得られる場合があります。
カスタムUICollectionViewクラスでうまく動作するようです。
class AutoSizedCollectionView: UICollectionView {
override var contentSize: CGSize {
didSet {
invalidateIntrinsicContentSize()
}
}
override var intrinsicContentSize: CGSize {
layoutIfNeeded()
return CGSize(width: UIView.noIntrinsicMetric, height: contentSize.height)
}
}
インターフェイスビルダーでカスタムクラスを設定します。
これにより、インターフェイスビルダーでコレクションビューの固有のサイズを「プレースホルダー」に設定して、高さの制約を設定する必要がなくなります。
これが他の人の助けになることを願っています。
以下に、固有のサイズを使用してCollectionViewの高さをバインドする方法を示します。 TableViewセル内のCollectionViewのサイズを動的に変更するために使用しました(動的セルの高さを使用)。完璧に機能します。
まず、これをUICollectionViewサブクラスに追加します。
override var intrinsicContentSize: CGSize {
get {
return self.contentSize
}
}
次に、データをリロードした後にlayoutIfNeeded()を呼び出します。
reloadData()
layoutIfNeeded()
私が見つけた最も簡単な方法は、sizeThatFits:
メソッドをそのままオーバーライドすることです:
- (CGSize)sizeThatFits:(CGSize)size
{
if( self.superview )
[self.superview layoutIfNeeded]; // to force evaluate the real layout
return self.collectionViewLayout.collectionViewContentSize;
}
カスタムAGCollectionView
クラスを試すことができます
UICollectionView
に割り当てます。class AGCollectionView: UICollectionView {
fileprivate var heightConstraint: NSLayoutConstraint!
override init(frame: CGRect, collectionViewLayout layout: UICollectionViewLayout) {
super.init(frame: frame, collectionViewLayout: layout)
self.associateConstraints()
}
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.associateConstraints()
}
override open func layoutSubviews() {
super.layoutSubviews()
if self.heightConstraint != nil {
self.heightConstraint.constant = floor(self.contentSize.height)
}
else{
self.sizeToFit()
print("Set a heightConstraint set size to fit content")
}
}
func associateConstraints() {
// iterate through height constraints and identify
for constraint: NSLayoutConstraint in constraints {
if constraint.firstAttribute == .height {
if constraint.relation == .equal {
heightConstraint = constraint
}
}
}
}
}