본문 바로가기
iOS

[iOS][SwiftUI] 달력 만들기

by teamnova 2023. 7. 4.

안녕하세요 오늘은 SwiftUI를 이용하여 달력을 만들어 보겠습니다.

 

코드는 아래와 같습니다.

struct ContentView: View {
    // 요일의 배열
    let daysInWeek = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]
    // 월의 배열
    let monthsInYear = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]
    
    // 날짜 포맷터
    var dateFormatter: DateFormatter {
        let formatter = DateFormatter()
        formatter.dateFormat = "yyyy-MM-dd"
        return formatter
    }
    
    // 표시할 날짜
    var date: Date {
        let components = DateComponents(year: 2023, month: 4, day: 1)
        return Calendar.current.date(from: components)!
    }
    
    var body: some View {
        VStack {
            // 년도와 월 표시
            Text("\(date.yearMonth)")
                .font(.title)
                .fontWeight(.bold)
            
            // 달력 표시
            LazyVGrid(columns: Array(repeating: .init(.flexible()), count: 7), spacing: 20) {
                // 요일 표시
                ForEach(daysInWeek, id: \.self) { day in
                    Text(day)
                        .font(.headline)
                        .fontWeight(.bold)
                        .frame(maxWidth: .infinity)
                        .padding(5)
                        .background(Color.blue)
                        .foregroundColor(.white)
                }
                // 날짜 표시
                ForEach(getDatesOfMonth(), id: \.self) { date in
                    Text("\(date.day)")
                        .font(.headline)
                        .frame(maxWidth: .infinity)
                        .padding(5)
                        .background(date.isToday ? Color.green : Color.white)
                        .foregroundColor(date.isToday ? Color.white : Color.black)
                }
            }
        }
    }
    
    // 해당 월의 모든 날짜를 가져오기
    func getDatesOfMonth() -> [Date] {
        // 해당 월의 일 수를 가져오기
        let range = Calendar.current.range(of: .day, in: .month, for: date)!
        // 해당 월의 모든 날짜를 가져오기
        let days = range.compactMap { day -> Date? in
            let components = DateComponents(year: date.year, month: date.month, day: day)
            return Calendar.current.date(from: components)
        }
        // 첫 번째 날이 시작하는 요일을 가져오기
        let firstDayOfWeek = Calendar.current.component(.weekday, from: date) - 1
        // 첫 번째 날 이전의 일부 날짜를 추가하여 첫 번째 날이 시작하는 요일로 맞추기
        let paddingDays = Array(repeating: Date(timeIntervalSince1970: 0), count: firstDayOfWeek)
        return paddingDays + days
    }
}

// Date 클래스의 확장
extension Date {
    // 년도 가져오기
    var year: Int {
        Calendar.current.component(.year, from: self)
    }
    // 월 가져오기
    var month: Int {
        Calendar.current.component(.month, from: self)
    }
    // 일 가져오기
    var day: Int {
        Calendar.current.component(.day, from: self)
    }
   
// 년도와 월을 문자열로 변환하기
	var yearMonth: String {
    let formatter = DateFormatter()
    formatter.dateFormat = "yyyy년 MM월"
    return formatter.string(from: self)
	}
// 오늘인지 확인하기
	var isToday: Bool {
    Calendar.current.isDateInToday(self)
	}
}


위 코드에 대한 주석은 다음과 같습니다.

- `daysInWeek`: 요일의 배열입니다.
- `monthsInYear`: 월의 배열입니다.
- `dateFormatter`: DateFormatter 인스턴스를 반환하는 계산 프로퍼티입니다. 이 프로퍼티는 날짜의 포맷을 설정합니다.
- `date`: 표시할 날짜입니다. 이 예제에서는 2023년 4월 1일로 설정합니다.
- `getDatesOfMonth()`: 해당 월의 모든 날짜를 가져오는 함수입니다. 이 함수는 해당 월의 일 수를 가져와서, 각 일에 해당하는 Date 인스턴스를 만듭니다. 또한, 첫 번째 날이 시작하는 요일을 가져와서, 이전 달의 몇 일을 추가하여 첫 번째 날이 시작하는 요일로 맞추어 배열에 추가합니다.
- `Date` 확장: `year`, `month`, `day`는 각각 년도, 월, 일을 가져오는 계산 프로퍼티입니다. `yearMonth`는 년도와 월을 문자열로 변환하는 계산 프로퍼티입니다. `isToday`는 날짜가 오늘인지 확인하는 계산 프로퍼티입니다.

이렇게 주석이 추가된 코드를 보면서, 달력을 구현하는 방법과 SwiftUI의 기능을 더욱 자세히 이해할 수 있습니다.