[Swift]UICollectionViewでカレンダーUIを作った際に、行数で高さを動的に変えるポイント

Swift

はじめに

この記事では、カレンダーの月によって行数が変化した際に、カレンダー全体の高さを動的に変更するポイントを紹介します。

結論

gifでは2021年5月は6行になるため、カレンダー全体の高さがそれに合わせて変化しています。

検証環境

端末バージョン
MacBig Sur 11.2.3
Xcode12.5
Swift5
iOS13.0
UIKit

前提条件

UIViewControllerのtop,right,bottom,leftにUICollectionViewを合わせてレイアウトを設定しています。

コード

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        let height = collectionView.collectionViewLayout.collectionViewContentSize.height
        if height != view.frame.size.height {
            heightConstraint = collectionView.heightAnchor.constraint(equalToConstant: height)
            heightConstraint?.isActive = true
            self.view.setNeedsLayout()
            self.view.layoutIfNeeded()
        }
    }
    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        collectionView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
        collectionView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
        collectionView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
        collectionView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true

        if let height = heightConstraint {
            height.isActive = false
            heightConstraint = collectionView.heightAnchor.constraint(equalToConstant: collectionView.collectionViewLayout.collectionViewContentSize.height)
            heightConstraint!.isActive = true
        }
    }

解説

viewDidAppearでレイアウトが確定したタイミングでUICollectionViewLayoutのcollectionViewContentSize.heightがカレンダー全体の高さと一致していなければNSLayoutConstraintに保持しています。

その後、viewDidLayoutSubviewsでNSLayoutConstraintに保持している高さを一度無効とし、再度高さを設定しています。
これはカレンダーの月を変更した場合に、前回登録している高さを一度無効化しておかなければ制約の重複が発生するためです。

当初はカレンダーの高さを取得するのにUICollectionView.contentSize.heightを使用していましたが、これだと次の月が表示された時点で、新しいカレンダーの高さが取得できなかったため、UICollectionViewLayoutのcollectionViewContentSize.heightを使用しています。(1つ前の月の高さのままでした)

参照

Apple Developer Documentation

コメント

タイトルとURLをコピーしました