1️⃣ 이 셀의 목표는 뭐야?
우리가 만들고 싶은 셀은 이렇게 생겼어:
✔ 기본 상태(접힘) — "대분류 감정 보기"
😀 행복
✔ 펼쳐진 상태 — "소분류 보기"
# 너무 좋아요
# 가슴이 설레요
# 신나요
...
즉,
- 처음에는 이모지 + 감정 이름(대분류) 만 보이고
- 셀을 누르면 대분류는 사라지고, 소분류 버튼 리스트가 보이도록 만들고 싶었던 거야.
이걸 위해서 한 개의 UI가 아니라 두 개의 UI 공간을 만든 것이 핵심이야.
2️⃣ 왜 baseContainer / subContainer 가 필요한가?
처음 코드는 이렇게 되어 있었어:
- baseContainer: 이모지 + 감정 이름
- subEmotionStack: 소분류 버튼들
문제는 baseContainer에다가 subEmotionStack까지 넣으려고 하면서 문제가 터졌어.
⚠️ 문제 발생 이유 — AutoLayout 충돌
baseContainer는
height == 120 같은 구체적인 높이 제약이 있었고,
subEmotionStack은 버튼이 많아질수록
height > 200, height > 300 … 이렇게 커지려 했어.
둘이 같은 parent 안에서 서로 높이가 싸우니까 이런 에러가 터진 거야:
Unable to simultaneously satisfy constraints.
UIView.height == 120
UIView.height == 184
즉,
- baseContainer는 “나 120이어야 해!”
- subEmotionStack은 “나는 컨텐츠가 많아서 184여야 해!”
서로 말이 안 맞아서 충돌🤯이 나온 거지.
3️⃣ 그래서 해결책은?
👉 “두 UI를 같은 뷰에 넣지 말자.”
그래서 우리는 구조를 이렇게 바꿨다:
contentView
├─ baseContainer (대분류)
└─ subContainer (여기에 subEmotionStack 포함)
그리고:
- 접힌 상태 → baseContainer 보임, subContainer 숨김
- 펼친 상태 → baseContainer 숨김, subContainer 보임
이렇게 두 개를 서로 토글(알파값 0 ↔ 1) 하면 제약 충돌이 완전히 사라짐!
왜냐하면:
- baseContainer는 고정 높이를 갖고 있을 필요도 없고,
- subContainer는 내부 버튼 내용 만큼 자연스럽게 늘어남
- 둘은 서로 간섭하지 않음
이 구조가 아주 중요한 핵심이야.
4️⃣ 실제로는 어떻게 숨기고 보여줄까?
정답은 alpha(투명도) 를 이용하는 것!
baseContainer.alpha = expanded ? 0 : 1
subContainer.alpha = expanded ? 1 : 0
즉,
- expanded == false → baseContainer 보임, subContainer 숨김
- expanded == true → baseContainer 숨김, subContainer 보임
그러면 뷰는 겹쳐있지만 하나는 보이고 하나는 안 보이니까 UI가 자연스럽게 바뀌는 것처럼 보임.
5️⃣ 애니메이션은 어떤 역할을 해?
우리가 넣은 애니메이션은 이것:
UIView.animate(withDuration: 0.25) {
self.layoutIfNeeded()
}
- alpha 값 변경 → 부드럽게 fade-in / fade-out
- layoutIfNeeded() → subContainer가 커지거나 줄어드는 걸 자연스럽게 애니메이션 처리
이 두 개가 합쳐져서
**“아래로 펼치는 느낌”**이 나게 되는 거야.
애니메이션 없으면 딱딱하게 “딱!” 하고 바뀌기 때문에 UI가 예쁘지 않지.
6️⃣ 그런데, 애니메이션을 셀 내부에서 하는 게 맞을까?
사실 100% 정답은 상황에 따라 달라.
지금 방식 (셀 내부에서 애니메이션)
- 장점: 셀 자체가 알아서 부드럽게 바뀜
- 단점: 컬렉션뷰 전체 레이아웃이 변경되는 상황에서는 조금 불안정할 수 있음
(특히 compositional layout + estimated height 조합)
더 안전한 방식 (EmotionStepCell → performBatchUpdates)
EmotionStepCell에서 이렇게 하는 방식:
collectionView.performBatchUpdates(nil)
이 방식의 장점:
- 레이아웃 엔진이 전체 셀의 높이 변화를 고려하고 처리
- 셀의 height 변화에 아주 안전함
- 의도치 않은 레이아웃 충돌 방지
그래서 실제로는
🔥 “layoutIfNeeded()는 셀 내부에서 하는 대신, 펼치기/접기 액션은 상위에서 batchUpdates로 처리하는 방식이 더 안정적이다.”
라고 말할 수 있어.
'감정일기(가칭)' 카테고리의 다른 글
| ❌ 한 셀만 열리고, 나머지는 닫히는 상태(sync)가 유지되지 않는다... (0) | 2025.12.08 |
|---|---|
| 🤔 왜 지금 애니메이션이 딱딱하게 보이고, fade-in/fade-out이 안 보이는지, 그리고 정확한 해결 방법까지 아주 명확히 설명 (0) | 2025.12.08 |
| 🍋 레몬로그 감정일기, 더 좋은 작성 경험을 위한 새로운 UX 구조 제안— Paging + Swipe 단계 진행 방식 도입기 (1) | 2025.12.06 |
| 🍋 LemonLog 홈 화면 UX 확장 아이디어 정리― 감정일기 앱에 가장 적합한 “가벼운 회고 + 동기 부여 + 패턴 인식” UX 설계 (1) | 2025.12.04 |
| 🍋 LemonLog UX 설계: 감성 기반 온보딩과 스트릭 기반 습관 형성 전략 (0) | 2025.12.04 |