[iOS/SwiftUI] Custom Week Calendar 구현하기
오늘은 Custom Week Calendar 구현 과정을 블로그에 기록해 보겠다!
진행하고 있는 프로젝트에서 주간 캘린더를 만들어야 하는데 기존 iOS에서 제공해주는 DatePicker를 사용하기엔 UI를 변경해야 하고, 기능적인 부분도 추가해야 했기에 그냥 커스텀 캘린더로 구현하였다.
디자인 팀 요구사항
- 처음 주간 캘린더 화면에 진입하게 될 시 오늘 날짜를 기준으로 포커싱 맞춰주기
- 소비내역이 없는 날과 소비내역이 있는날의 글자색과 배경색이 달라져야 함
- 현재보다 미래 날짜에 대해선 선택 불가능 하도록 (클릭해도 아무런 액션 x)
기능 구현
전체 적인 주간 캘린더를 커스텀 하는 건 다른 블로그를 참고했다.
그래서 지금 포스팅하는 건 위 디자인팀 요구사항을 충족시키는데 필요했던 과정들에 대해서 설명해보고자 한다!
1️⃣ 처음 화면에 진입하게 될 시 오늘 날짜를 기준으로 포커싱 맞춰주기
이 기능을 동작하게 하기 위해선 오늘날짜를 설정해줘야 하는 변수가 있어야 하고 onAppear를 통해 스크롤링되도록 구현해야겠다고 생각했다.
init(
spendingHistoryViewModel: SpendingHistoryViewModel,
selectedDateToScroll: Binding<String?>
) {
self.spendingHistoryViewModel = spendingHistoryViewModel
_selectedDateToScroll = selectedDateToScroll
}
var body: some View {
ScrollViewReader { scrollProxy in
VStack(alignment: .leading, spacing: 15 * DynamicSizeFactor.factor()) {
monthView
ZStack(alignment: .top) {
dayView
}
.frame(height: 40 * DynamicSizeFactor.factor())
.padding(.horizontal, 10)
}
.padding(.bottom, 6)
.padding(.top, 8)
.onChange(of: spendingHistoryViewModel.selectedDateToScroll) { newValue in
if let newDateStr = newValue, let date = DateFormatterUtil.parseDate(from: newDateStr) {
selectedDate = date
withAnimation {
scrollProxy.scrollTo(date, anchor: .center)
}
}
}
.onAppear {
proxy = scrollProxy
setToToday()
scrollToDate(proxy: scrollProxy)
}
}
}
...
// 오늘 날짜를 기준으로 포커싱 해주는 함수
private func setToToday() {
selectedDate = Date()
selectedDateToScroll = dateFormatter(date: Date())
spendingHistoryViewModel.selectedDateToScroll = dateFormatter(date: Date())
}
// 사용자가 선택한 날짜로 스크롤하는 함수
private func scrollToDate(proxy: ScrollViewProxy?) {
if let dateToScroll = selectedDateToScroll, let date = DateFormatterUtil.parseDate(from: dateToScroll) {
proxy?.scrollTo(date, anchor: .center)
}
}
- setToToday : 현재 날짜를 받아와서 viewModel에 있는 selectedDateToScroll에 현재 날짜를 넘겨주는 함수
- scrollToDate: 사용자가 선택한 날짜로 스크롤가능하게 해주기 위하여 타입을 변환하는 과정을 거쳐주는 함수
위에 두 함수를 통해서 뷰가 onAppear 될 때, 현재날짜를 기준으로 스크롤되도록 구현해 주었고 onChange를 통해 사용자가 다른 날짜를 스크롤했을 경우 그 날짜에 대한 지출내역이 보이도록 구현하였다!
이 코드는 이전 포스팅을 참고하면 될 듯 하다!
2024.06.28 - [iOS/SwiftUI] - [iOS/SwiftUI] ScrollViewReader를 사용해 스크롤링 감지하기
[iOS/SwiftUI] ScrollViewReader를 사용해 스크롤링 감지하기
오늘은 ScrollViewReader에 대해 알아보자 먼저 ScrollView와 ScrollViewReader는 무엇이 다른걸까?? ScrollView 스크롤 뷰는 단순히 스크롤 할 수 있는 뷰를 의미한다!그래서 스크롤이 가능한 뷰에 사용하고
yanni13.tistory.com
2️⃣ 소비내역 유무에 따라 배경색과 글자색이 변경돼야 함
private func circleColor(for date: Date) -> Color {
if calendar.isDateInToday(date) {
return Color("Mint01")
} else if let userSelected = userSelectedDate,
calendar.isDate(userSelected, equalTo: date, toGranularity: .day)
{
if spendingHistoryViewModel.getDailyTotalAmount(for: date) != nil {
return Color("Gray03")
} else {
return Color("Gray02")
}
} else {
return Color.clear
}
}
private func textColor(for date: Date) -> Color {
if calendar.isDateInToday(date) {
return Color("Mint03")
} else if spendingHistoryViewModel.getDailyTotalAmount(for: date) == nil {
return Color("Gray03")
} else if calendar.isDate(selectedDate, equalTo: date, toGranularity: .day) {
return spendingHistoryViewModel.getDailyTotalAmount(for: date) == nil ? Color("Gray04") : Color("Gray05")
} else {
return Color("Gray06")
}
}
총 3가지의 예외처리가 존재한다.
- 과거 내역에서 사용자가 클릭을 했는데 지출내역이 없는 경우
- 현재날짜(오늘 날짜)인 경우
- 사용자가 클릭을 하지 않아도 지출내역이 없는 경우
1번인 경우에는 UserSelected로 사용자가 선택한 날에서 조건문을 또 실행하여 뷰모델에 있는 dailyTotalAmount(즉 하루 총지출금액)을 확인한 후 nil 값일 경우와, 아닐 경우에 대한 색상처리를 해주고 있다.
2번인 경우 현재날짜를 조회하여 Mint값을 되돌려주고 있다.
3번일 경우에는 CircleColor에서 현재 날짜보다 미래 날짜에 대한 예외처리는 모두 else 문으로 넘어가기 때문에 별다른 액션이 취하지 않게 구현하였다.
구현한 UI
- 첫 화면 진입시 -> 현재 날짜를 보여줌
- 현재보다 미래 날짜에 대해 클릭해도 아무런 이벤트 x
- 지출내역이 있는 날짜/ 없는 날짜에 대한 색상이 다름
- 지출내역이 있는 날짜를 선택했을 경우 해당 날짜로 아래 내역이 스크롤링됨
- 지출내역이 있다면 날짜 밑에 금액 표시
나름 엄청 열심히 했는데 공들인 만큼 기능적으로도, 디자인 적으로도 마음에 들어서 좋았다,,!!
완성된 기능을 짤로 보면 아래와 같다.
마무리
프로젝트 처음 시작했을 때는 api 연동조차 할 줄 모르고 UI 구현하는 데에 시간도 오래 걸렸었는데 점점 개발 속도도 빨라지고 실력도 성장해 가는 거 같아서 너무 뿌듯하다!
더 열심히 해서 마스터의 경지까지 도달하도록 .. 노력해야쥐..
더 자세한 코드는 아래 깃허브에서 확인할 수 있다!
pennyway-client-ios/pennyway-client-iOS/pennyway-client-iOS/View/TabView/SpendingManagementView/SpendingManagementMainView/Spend
🪙 Pennyway iOS Mobile Client. Contribute to CollaBu/pennyway-client-ios development by creating an account on GitHub.
github.com