팀플 작업중, 버튼으로는 도저히 CollectionView cell 크기를 동적으로 변경하기가 어렵다는 연락을 받았습니다
이 부분을 위해 버튼을 열심히 구현했던 저는 슬픔에 빠졌었죠.. (10초 정도)
다시 생각해보니 저는 이걸 구현하는 방법을 알고 있어요
저는 다이나믹하게 동작하는 ui를 제법 좋아하기 때문에 공부하면서 찾아본 적이 있었기 때문이죠
직접 구현한 적은 없었지만..
지금 하면 되는 거 아님?
🩵 동적 Cell 크기 계산의 장점
셀의 크기를 콘텐츠의 크기에 기반해서 결정하면
다양한 크기의 콘텐츠를 유연하게 표시할 수 있습니다!
이런 유연한 콘텐츠는 앱의 UI를 조금 더 풍부하고 상호작용적인 느낌으로 만들어줘요
콘텐츠에 기반한 셀 크기는 사용자에게 뭔가 "맞춤형"이라는 느낌을 주고
각각의 콘텐츠가 최적화 된 공간만을 차지하기 때문에 정보를 받아들이는 데도 효과적일 거에요
또한 디바이스의 크기, 방향등에 관계 없이 콘텐츠를 최적화 시켜서 보여줄 수 있어요
반응형 디자인을 하는 데도 아주 중요한 요소가 되겠네요!
동적으로 Cell 크기를 계산하는 것은 이렇게 UI를 풍부하게 만들어 줄 뿐만 아니라
UX(사용자 경험)도 최적화 시킬 수 있고,
앱의 매력을 한 층 끌어올려줄 것 같아요
🩵 collectionView(_:layout:sizeForItemAt:) 메서드
셀 크기를 정해주는 collectionView의 메서드입니다
CGSize라는 타입으로 너비, 높이(width, height) 값을 반환해서 사용할 수 있네요!
이 값은 반드시 0보다 커야 합니다
optional func collectionView(
_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAt indexPath: IndexPath
) -> CGSize
이 메서드를 사용하지 않는다면 기본적으로 셀 내부 속성의 값을 사용해서 자동으로 항목의 크기를 결정한다고 해요
구현한다면? 고정된 크기를 반환해주거나 셀 내용에 따라 크기를 동적으로 조정할 수 있어요!
여기까지 전부 공식 문서에 작성된 부분입니다ㅎㅎ
저는 어떤 방식으로 해볼까 고민하다가,
현재 구현하는 부분은 내용이 텍스트뿐이라서 텍스트를 이용해보려고 결정했어요
🩵 임시 텍스트 만들어서 크기 결정하기
우선 indexPath.row 와 실제로 사용하는 데이터를 활용하여 임시 텍스트를 하나 만들어줘요
이 때, 셀 내부에서 따로 사용중인 폰트 사이즈가 있다면 해당 부분도 꼭 지정해줘야 합니다!
let title = buttons[indexPath.row].title
let font = TDStyle.font.body(style: .regular) // 버튼의 실제 폰트 크기와 일치
두 정보를 기반으로 사이즈를 잡아주어요
let size = title.size(withAttributes: [.font: font])
여백을 추가해서 콘텐츠끼리 너무 딱 붙지 않게 만들어줄게요
그리고 나서 필요한 사이즈에 여백을 더해서 반환시키면 끝입니다!
let padding: CGFloat = 20 // 좌우 여백 추가
let cellWidth = size.width + padding
전체코드는 요렇게 되어요
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let title = buttons[indexPath.row].title
let font = TDStyle.font.body(style: .regular) // 버튼의 실제 폰트 크기와 일치
let size = title.size(withAttributes: [.font: font])
let padding: CGFloat = 20 // 좌우 여백 추가
let cellWidth = size.width + padding
return CGSize(width: cellWidth, height: collectionView.bounds.height)
}
❗ 다른 방법은? - size(withAttributes:)
size(withAttributes:) 라는 크기 반환 메서드를 사용하셔도 좋을 것 같아요!
https://developer.apple.com/documentation/foundation/nsstring/1531844-size
해당 메서드를 사용한다면?
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let cellSize = CGSize(width: buttons[indexPath.item].title.size(
withAttributes: [NSAttributedString.Key.font : TDStyle.font.body(style: .regular)]
).width + 20, height: collectionView.bounds.height)
return cellSize
}
이렇게 더 간결하게 사용할 수 있겠네요!!
가독성은 약간 더 떨어지지만 명확하고 코드가 짧아서 좋습니다ㅎ
✅ 구현 완료 화면
요런 느낌으로 구현이 완료되었습니다!
버튼이기 때문에 addTarget을 사용해서 바로 셀렉터도 넣어줄 수 있어요
사실 스택뷰를 사용하면 선형 레이아웃을 만들기고 쉽고 자동으로 너비를 조정해주기도 하니까 이건 어떨까 했는데
저희 프로젝트는 하단에 리스트가 또 들어갈 예정이거든요
그래서 아마 컬렉션뷰로 해본다고 하셨던 거 같네요? (가물가물..)
어쨌든 대충 알고는 있었지만 구현해보진 않은 부분! 이번 기회에 해봤습니다
~ヾ(^∇^)
https://developer.apple.com/documentation/uikit/uicollectionviewdelegateflowlayout/1617708-collectionview
https://stackoverflow.com/questions/30481931/how-to-get-the-correct-width-of-a-uilabel-after-the-text-has-been-set
'iOS > Swift' 카테고리의 다른 글
[Swift] 열거형 Enumeration / 타입 안정성 (0) | 2024.03.04 |
---|---|
[Swift] iOS 알림 설정 허용받기 - User Notifications (0) | 2024.03.02 |
[Swift] 프레임워크와 라이브러리 (3) 접근제한자 (0) | 2024.02.29 |
[Swift] 프레임워크와 라이브러리 (2) UIKit SnapKit으로 비교하기 (0) | 2024.02.27 |
[Swift] 프레임워크와 라이브러리 (1) (0) | 2024.02.26 |