CollectionView Cell 동적 크기 구성하기
===
[TOC]
### UICollectionViewCell
#### Cell 동적 크기 결정 방법 intrinsicContentSize를 활용해서 해결하기
Dynamic Cell Width
Cell 내 Label Size에 맞춰 Cell Width 결정하기
|ex)| |
|---|-----------------------------------------------|
#### **1. Cell 객체 생성 후 데이터를 넣어서 frame size 결정하기**
intrinsicContentSize: 내용을 기반으로 하는 고유 크기 계산하는 방법
> 사용 가능 메서드
> 
- **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`