web-dev-qa-db-ja.com

UICollectionViewの自動サイズ調整の高さ

UICollectionViewを適切にサイズ変更して、コンテンツを完全に表示するにはどうすればよいですか?フレームの設定、reloadDataの呼び出し、レイアウトの無効化など、多くのことを試しました。

self.collectionView.contentSize = CGSizeMake(300, 2000);
self.collectionView.frame = CGRectMake(0, 0, 300, 2000);
[self.collectionView reloadData];
[self.collectionView.collectionViewLayout invalidateLayout];

しかし、これは効果がありません。ボタンを押した後、次のような初期ビューがまだ表示されます。

collection view only showing part of the content after frame resize

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}

フレームの変更が保持されない理由がわかりません。何が変更されているのですか。

ある時点で、ハードコーディングされた値をフローレイアウトから取得した値に置き換えますが、それを除外し、私の例をできるだけシンプルに保ちたいと思いました。

コンテキスト:最終的にやりたいことは次のとおりです。ラベルや画像などのさまざまなコントロールを備えたスクロール可能なビューと、動的コンテンツを備えたコレクションビューがあります。コレクションビューだけでなく、すべてをスクロールしたいので、コレクションビューの独自のスクロール機能を使用していません。

49

最終的には、すべての自動レイアウトの問題を修正し、制約を使用してコレクションビューの高さを修正することでこれを解決しました。その後、コンテンツが変更されたことがわかっているときは常に、値collectionView.contentSize.heightを使用して制約の値を更新します。

self.verticalLayoutConstraint.constant = self.collectionView.contentSize.height;

次に、コレクションビューのサイズが適切に変更され、全体的なスクロールビュー内で適切に動作します。 GitHubテストプロジェクトを変更して更新しました。

私にとっては、iOSに「コレクションビューのフレームの高さを必要に応じて大きくする」のではなく、制約を手動で更新することでこれを行うことは適切ではありませんが、私が来た最高の方法ですこれまでのところ。もしあればもっと良い答えを投稿してください。

105

Swift 3:

override func sizeThatFits(_ size: CGSize) -> CGSize {
    if (self.superview != nil) {
        self.superview?.layoutIfNeeded()
    }

    return collectionView.contentSize
}
3
Craig Holliday
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を使用してアイテムのサイズを調整すると、希望する結果が得られる場合があります。

2
flame3

カスタムUICollectionViewクラスでうまく動作するようです。

class AutoSizedCollectionView: UICollectionView {

    override var contentSize: CGSize {
        didSet {
            invalidateIntrinsicContentSize()
        }
    }

    override var intrinsicContentSize: CGSize {
        layoutIfNeeded()
        return CGSize(width: UIView.noIntrinsicMetric, height: contentSize.height)
    }
}

インターフェイスビルダーでカスタムクラスを設定します。

enter image description here

これにより、インターフェイスビルダーでコレクションビューの固有のサイズを「プレースホルダー」に設定して、高さの制約を設定する必要がなくなります。

enter image description here

これが他の人の助けになることを願っています。

2
Trevor

以下に、固有のサイズを使用してCollectionViewの高さをバインドする方法を示します。 TableViewセル内のCollectionViewのサイズを動的に変更するために使用しました(動的セルの高さを使用)。完璧に機能します。

まず、これをUICollectionViewサブクラスに追加します。

override var intrinsicContentSize: CGSize {
    get {
        return self.contentSize
    }
}

次に、データをリロードした後にlayoutIfNeeded()を呼び出します。

reloadData()
layoutIfNeeded()
2
AmitP

私が見つけた最も簡単な方法は、sizeThatFits:メソッドをそのままオーバーライドすることです:

- (CGSize)sizeThatFits:(CGSize)size
{
    if( self.superview )
        [self.superview layoutIfNeeded]; // to force evaluate the real layout

    return self.collectionViewLayout.collectionViewContentSize;
}
1
Nicolas Buquet

カスタムAGCollectionViewクラスを試すことができます

  • ストーリーボードを使用するか、プログラムでcollectionViewの高さの制約を割り当てます。

-このクラスを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
                }
            }
        }
    }
}
0
AshvinGudaliya