

감정일기를 작성하는 6단계 UI를 만들면서,
마지막 단계(6/6)에서 날짜 + 사진을 선택하는 화면을 구현해야 했다.
처음엔 단순히 UILabel로 “2025년 12월 10일” 같은 표시만 하고,
여기를 탭하면 날짜를 선택하게 만들면 되겠다고 생각했다.
문제는 날짜 선택 UI를 어떻게 노출할 것이냐였다.
1. 두 가지 설계안 비교하기
날짜를 선택하는 UI는 크게 두 방향으로 구현할 수 있었다.
① Label을 탭 → Bottom Sheet → 달력 뷰 띄우기
(달력은 따로 만든 UICollectionView 기반 CalendarVC 사용)
이 방식은 카카오톡, 슬랙, 노션 등 대부분의 앱에서 사용하는 형태이다.
필요할 때만 달력이 화면에 나타나고, 선택하면 즉시 내려간다.
② 마지막 단계 셀 내부에 달력을 직접 넣기
(Cell 안에 UICollectionView를 그대로 넣어서 달력 UI 전체를 표시)
즉, DiaryWriteDateAndGalleryCell 내부 UI로 달력 전체가 들어가 버리는 구조다.
두 구현 모두 한 화면 안에서 날짜를 선택할 수 있다는 점에서는 동일하지만,
장기적인 유지보수와 UX 기준에서는 큰 차이가 있다.
2. 결론: 두 방식 중 정답은 ① Bottom Sheet 방식
간단히 말하면,
👉 Label을 탭하면 Bottom Sheet로 날짜 선택 화면을 띄우는 방식이 압도적으로 더 좋다.
왜 그런지 UI/UX · 아키텍처 · 성능 관점으로 하나씩 정리해보자.
3. 왜 Bottom Sheet 방식이 더 좋은가?
✔ 3-1. 현재 작성 단계UI 흐름과 가장 자연스럽게 맞기 때문
지금 감정일기 작성 UI는 총 6단계(step-by-step) 로 구성되어 있다.
- emotion
- situation
- thought
- reeval
- action
- dateAndImages ← 마지막 단계
여기서 갑자기 큰 달력 UI가 나타나면?
- UI 맥락이 갑자기 바뀜
- 마지막 단계가 "요약/완성" 느낌인데 갑자기 UI가 너무 무거워짐
- 화면 높이를 차지하는 요소가 늘어나면서 스크롤이 길어짐
반대로,
“날짜를 선택하세요 → 라벨 표시 → 탭하면 달력”
이라는 구조는 작성 흐름을 전혀 방해하지 않음.
✔ 3-2. 달력을 셀 안에 넣는 것은 메모리·성능 측면에서 비효율적
내가 만든 달력은 UICollectionView 기반이라:
- 월 데이터 모델
- 날짜 셀 렌더링
- 선택 상태 관리
- diffable datasource 적용
이런 내부 로직이 이미 복잡하다.
이걸 DiaryWrite의 셀 안에 넣으면,
- 셀 재사용 과정에서 상태 꼬일 위험
- 스크롤 시 매번 달력 로직이 호출됨
- 셀이 두 개만 있어도 달력 뷰가 여러 번 만들어짐
- 메모리 사용량이 불필요하게 증가함
즉, 달력은 독립적인 ViewController로 다루는 것이 가장 합리적이다.
✔ 3-3. UX 측면에서도 Bottom Sheet가 더 익숙하고 부담이 없다
대부분의 앱이 날짜 선택을 아래 방식으로 처리한다:
- iOS 기본 DatePicker → bottom sheet
- 카카오톡 일정 → bottom sheet
- 구글 캘린더도 modal/calendar picker 사용
사용자 입장에서도,
현재 화면을 유지한 채, 일부 UI만 위로 올려서 선택하는 구조가
훨씬 자연스럽고 피로도가 낮다.
✔ 3-4. 유지보수 및 확장성이 훨씬 좋다
Bottom Sheet 방식의 핵심 장점:
- CalendarViewController를 재사용 가능
- 다른 기능에서도 날짜 선택 UI가 필요하면 그대로 이용 가능
- 작성 화면과 달력 로직이 깔끔히 분리됨
- MVVM 구조에 맞게 역할 분리가 쉬움
반대로 셀 내에 달력을 넣으면:
- 로직이 뭉치고
- 셀의 책임 범위가 비대해지고
- 기능 확장이 매우 어렵다
4. 실제 구현 구조 (추천 아키텍처)
4-1. Cell(마지막 스텝)의 역할
- 현재 선택한 날짜 표시(label)
- label 탭 → onTapDatePicker 콜백 호출
var onTapDatePicker: (() -> Void)?
4-2. ViewController의 역할
- label 탭 시 → Bottom Sheet 띄우기
cell.onTapDatePicker = { [weak self] in
self?.presentDatePickerSheet()
}
4-3. CalendarViewController의 역할
- 달력 UI 그리기
- 날짜 선택 후 onDateSelected 호출
var onDateSelected: ((Date) -> Void)?
4-4. 선택된 날짜가 오면 ViewModel에 저장
datePicker.onDateSelected = { [weak self] date in
self?.viewModel.updateDate(date)
self?.reloadCell(for: .dateAndImages)
}
5. 실제 앱 흐름 예시
[감정일기 작성 6단계 화면]
⬇
[날짜 라벨 탭]
⬇
[Bottom Sheet로 달력 띄움]
⬇
[날짜 선택 → sheet 닫힘]
⬇
[Cell 라벨 자동 업데이트]
6. 최종 결론
달력을 직접 셀에 넣는 방식
→ UI 무거워짐 · 메모리 비효율 · 재사용 문제 · 구조 복잡
Label + Bottom Sheet 방식(달력은 독립 VC)
→ UI 깔끔 · UX 친숙 · 유지보수 쉽고 확장성 높음 · 아키텍처적으로도 정석
따라서 감정일기 작성 마지막 단계에서
날짜 선택 UI를 구현할 때는,
🎯 “라벨을 탭하면 Bottom Sheet로 달력 ViewController를 띄우는 방식을 사용한다.”
'감정일기(가칭)' 카테고리의 다른 글
| 📅 날짜 선택 → 감정일기 리스트 화면 설계하기 (LemonLog 사례) (0) | 2025.12.16 |
|---|---|
| 📱 UICollectionView 내부 셀의 날짜 갱신이 안 되는 이유와 해결 방법— 특히 “셀 자체를 전달하는 방식”의 강력함 (0) | 2025.12.10 |
| 📘 단계형 UI(Form Wizard)에서 유효성 검사를 어떻게 설계할까?— 감정일기 작성 화면(DiaryWrite)을 구현하면서 얻은 설계 인사이트 (0) | 2025.12.09 |
| 📘 DiaryWriteViewController 설계 문서 (함수·프로퍼티 단위 상세 버전) (0) | 2025.12.09 |
| 📘 DiaryWriteViewModel – 설계 문서 (Logic Blueprint) (0) | 2025.12.09 |