CollectionView Cell 동적 크기 구성하기 === [TOC] ### UICollectionViewCell #### Cell 동적 크기 결정 방법 intrinsicContentSize를 활용해서 해결하기 Dynamic Cell Width Cell 내 Label Size에 맞춰 Cell Width 결정하기 |ex)| ![add margin](https://i.imgur.com/ka48Bxa.png)| |---|-----------------------------------------------| #### **1. Cell 객체 생성 후 데이터를 넣어서 frame size 결정하기** intrinsicContentSize: 내용을 기반으로 하는 고유 크기 계산하는 방법 > 사용 가능 메서드 > ![function Image](https://i.imgur.com/RNYcxAH.png) - **sizeToFit()** : **텍스트**에 맞게 라벨의 크기 - **sizeThatFits()** : **지정된 크기**에 적합한 크기 > -> 반환된 크기를 가지고 width/height 중 원하는 것을 조정할 수 있음. > Label, TextView 등 높이 값을 유동적으로 조정할 때 많이 사용한다. sizeThatFits() 메서드만 사용할 경우, UILabel의 intrinsicContentSize로 인해 UILabel 내부의 텍스트를 가지게 된다. - 주로 sizeThatFits은 Label, TextView 등 높이값을 유동적으로 조정하기 위해 많이 사용. 먼저 sizeToFit() 텍스트에 맞는 적절한 라벨의 크기를 결정하고, 이에 맞는 비율은 sizeThatFits() 메소드를 사용하는 방식으로 구성할 수 있음. ```swift= // 셀이 가지고 있는 titleLabel의 텍스트 크기에 맞게 라벨의 크기를 조절 cell.titleLabel.sizeToFit() // 셀을 titleLabel의 크기에 라벨의 크기에 맞게 조절 let cellSize = cell.sizeThatFits(cell.titleLabel.frame.size) // 셀 width, height 반환 let cellWidth = cellSize.width let cellHeight = cellSize.height return CGSize(width: cellWidth, height: cellHeight) ``` sizeThatFits()만 사용할 경우, Label의 크기와 cell의 크기가 동일함. sizeThatFits -> 이미 정해진 라벨의 크기에 셀의 크기를 맞춘 것 ```swift= enum Constraint { static let verticalInset: CGFloat = 20 static let horizontalInset: CGFloat = 20 } func collectionView(_: collectionView, _: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) // 실제 델리게이트 메소드가 실행될 경우엔 Inset을 추가함. // sizeThatFits 실행 시 오로지 글씨 크기에 대한 계산만 이뤄졌기 때문 let cellWidth = cellSize.width + Constraint.horizontalInset let cellHeight = cellSize.height + Constraint.verticalInset return CGSize(width: cellWidth, height: cellHeight) ``` #### **2. UILabel 만들고, 텍스트 데이터를 넣어서 frame size 결정** 위 방법과 비슷하지만, Cell이 아닌 Label만 생성하면 **IntrinsicContentSize**이 계산되고, 계산된 width를 활용해서 Inset을 추가해주는 방법임. cell 객체를 가져오진 않아도 되지만, 지금의 경우처럼 cell 내부에 UIView 요소로 UILabel 하나만 있는 경우처럼 intrinsicContentSize의 계산이 유효한 경우에만 사용할 수 있는 방법. ```swift= enum Constraint { static let horizontalInset: CGFloat = 20 } // MARK: width 반환 func calculateWidth(_ index: Int) -> CGFloat { let label = UILabel() let fontSize = 15 label.text = datasource[index] label.font = .systemFont(ofSize: fontSize) label.sizeToFit() return label.frame.width + Constraint.horizontalInset } ``` SizeForItemAt delegate method 내부에서 호출 진행 ```swift= func collectionView(_: collectionView, _: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) { let cellWidth = calculateWidth(index) // height의 경우, 1번 경우 활용 } ``` #### **3. NSString을 사용하는 방법** 해당 셀에 들어갈 정보 datasource에 해당하는 텍스트에 대해서 font, size를 부여하고, bounding box size를 활용해서 width를 계산하고, Inset을 추가해서 사이즈 결정 ```swift= enum Constraint { static let verticalInset: CGFloat = 20 static let horizontalInset: CGFloat = 20 } let fontSize = 15 CGSize(width: datasource[indexPath.item].size(withAttributes: [NSAttributedString.Key.font : UIFont.systemFont(ofSize: fontSize)]).width + Constraint.horizontalInset, height: height + Constraint.verticalInset) ``` **참고** --- https://xodhks0113.blogspot.com/2019/08/ios-sizetofit-vs-sizethatfits.html https://gyuios.tistory.com/124 https://sihyungyou.github.io/iOS-collectionView-selfsizing-cell-2/ ###### tags: `UICollectionViewCell`, `UIKit`, `dynamic cell size`