Swift UICollectionViewのcellサイズを自動調整する


概要

UICollectionViewのcellサイズを中のコンテンツサイズに応じて自動調整する。

下イメージではUIButtonを横スクロールするUICollectionViewに並べた。UIButtonのサイズだけ、cellの横幅を自動調整している。

f:id:letitride:20190901111839p:plain:h400

estimatedItemSizeを指定すると楽に設定することができる。TableViewのtableView.rowHeight = UITableViewAutomaticDimensionのようなもの。

UICollectionViewとUICollectionViewCellはstoryboardに配置されているものとする。


前提

cell内に配置する各Viewの配置位置を適切にautolayoutで配置しておく。例えば、配置するUIButtonはtop,bottom,left,rightともにcell幅一杯に配置するなど。


設定

collectionViewLayout.estimatedItemSizeUICollectionViewFlowLayout.automaticSizeを設定する。estimatedItemSizeはUICollectionViewFlowLayoutにダウンキャストしないと参照できない。

override func viewDidLoad() {
    super.viewDidLoad()
    if let flowLayout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout {
        flowLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize
    }
}


cell自体の制約を定義

cell自体の制約を定義を行わないとサイズが調整されない。

対象cellのクラスファイルを作成し、awakeFromNib()メソッドに以下の定義を追加する。

storyboard上のオブジェクトに対しての紐付けも忘れずに。

class CollectionViewCell: UICollectionViewCell {
    
    override func awakeFromNib() {
        super.awakeFromNib()
         
        self.contentView.translatesAutoresizingMaskIntoConstraints = false
        let leftConstraint = self.contentView.leftAnchor.constraint(equalTo: self.leftAnchor)
        let rightConstraint = self.contentView.rightAnchor.constraint(equalTo: self.rightAnchor)
        let topConstraint = self.contentView.topAnchor.constraint(equalTo: self.topAnchor)
        let bottomConstraint = self.contentView.bottomAnchor.constraint(equalTo: self.bottomAnchor)
        NSLayoutConstraint.activate([leftConstraint, rightConstraint, topConstraint, bottomConstraint])
    }

}

参考

UICollectionViewFlowLayoutのestimatedItemSizeを指定するとiOS12で表示がおかしい - Qiita


付録 自動調整したcell内のviewに余白をとりたい

cell内viewのサイジングは制約確定前に行う必要があるみたい。storyboardやViewController側で行うとおかしな挙動になった。

class CollectionViewCell: UICollectionViewCell {

    @IBOutlet weak var tagNameButton: UIButton!

    override func awakeFromNib() {
        super.awakeFromNib()
        
        //余白の調整処理
        button.contentEdgeInsets = UIEdgeInsets(top: 5.0, left: 7.0, bottom: 5.0, right: 7.0)
        button.titleLabel?.adjustsFontSizeToFitWidth = true

        self.contentView.translatesAutoresizingMaskIntoConstraints = false
        let leftConstraint = self.contentView.leftAnchor.constraint(equalTo: self.leftAnchor)
        let rightConstraint = self.contentView.rightAnchor.constraint(equalTo: self.rightAnchor)
        let topConstraint = self.contentView.topAnchor.constraint(equalTo: self.topAnchor)
        let bottomConstraint = self.contentView.bottomAnchor.constraint(equalTo: self.bottomAnchor)
        NSLayoutConstraint.activate([leftConstraint, rightConstraint, topConstraint, bottomConstraint])
    }

}