ToDoList 만들기 (5) 캘린더 추가

2024.03.19 - [◽️ Programming/T I L] - ToDoList 앱 만들기 (1)

2024.03.21 - [◽️ Programming/T I L] - ToDoList 앱 만들기 (2)

2024.03.25 - [◽️ Programming/T I L] - ToDoList 앱 만들기 (3)

2024.03.27 - [◽️ Programming/T I L] - ToDoList 앱 만들기 (4)

ToDoList 만들기 (5) 캘린더 추가

오늘은 과제에서 요구하는 필수 구현요소를 다 구현한 뒤 마감전까지 완성할 수 있는 기능을 하나 넣는 정도로 마무리 하였다!

그것은 바로 어제 탭바만 추가한 캘린더를 추가한 것이었다.

원래 더 많은 기능을 구현하고 싶었지만 일단 제출을 해야하므로 과제와는 별개로 앞으로 코어데이터, 캘린더 이벤트추가 등 배우는 내용을 토대로 앱을 완성시켜 나갈 계획이다.


캘린더 추가

먼저 캘린더를 추가하는 방법은 애플에서 이미 캘린더를 쉽게 구현할 수 있도록 만들어뒀기 때문에 잘 불러오기만 하면 손쉽게 구현이 가능했다.

다만 이 기능은 iOS 16 이상 버전에서만 작동한다 🙂

먼저 캘린더 코드를 넣어주고 연결할 뷰컨트롤러를 새로 만들어 준비한다.

이때 UIKit 이 임포트 되어있어야 구현이 가능하다!

MARK: - 코드베이스로 캘린더 호출
lazy var dateView: UICalendarView = {
    var view = UICalendarView()
    view.translatesAutoresizingMaskIntoConstraints = false
    view.wantsDateDecorations = true
    return view
}()

MARK: - 캘린더 오토레이아웃
fileprivate func applyConstraints() {
    view.addSubview(dateView)
    let dateViewConstraints = [
        dateView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
        dateView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor),
        dateView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
        dateView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor)
    ]
    
    NSLayoutConstraint.activate(dateViewConstraints)
}

먼저 코드를 베이스로 만들어줄 예정이기 때문에 UICalendarView 를 호출해 변수에 담아주고 정상적으로 view 위에 나올 수 있도록 설정한다.

그 이후 오토레이아웃을 설정해 캘린더의 위치를 잡아준다!

처음 구현했을 당시 바텀 앵커를 잡아주지 않아 캘린더가 애매하게 2/3 정도 위치하게 구현되어있어 바텀앵커를 잡아주니 원하는 만큼 크기가 늘어나 깔끔하게 구현될 수 있었다.

  • 여기서 wantsDateDecorations 란?

ㄴ 기본값은 true이고 달력 Custom 하기 위해 설정해야 하는 속성이다.


캘린더 내 특정 일자 선택 시 이벤트 구현

이렇게 구현만 하고 끝내기는 아쉬운 마음이기도 하고 이후 기능을 추가할 예정이기 때문에 캘린더 내 델리게이트를 활용하여 기능을 더 확장해보려고 한다.

먼저 기능을 확장하기 위해 델리게이트를 활용하여 권한을 부여해주자

// MARK: - 캘린더 델리게이트 선언
    fileprivate func setCalendar() {
        dateView.delegate = self
        
        let dateSelection = UICalendarSelectionSingleDate(delegate: self)
        dateView.selectionBehavior = dateSelection
    }
    
    func reloadDateView(date: Date?) {
        if date == nil { return }
        let calendar = Calendar.current
        dateView.reloadDecorations(forDateComponents: [calendar.dateComponents([.day, .month, .year], from: date!)], animated: true)
    }
    
}

// MARK: - 캘린더 뷰 컨트롤러 델리게이트 확장 ( 단일 날짜 선택에 대한 변경 사항을 처리 )
extension CalenderViewControllar: UICalendarViewDelegate, UICalendarSelectionSingleDateDelegate {
    func calendarView(_ calendarView: UICalendarView, decorationFor dateComponents: DateComponents) -> UICalendarView.Decoration? {
        if let selectedDate = selectedDate, selectedDate == dateComponents {
            return .customView {
                let label = UILabel()
                label.text = "🐶"
                label.textAlignment = .center
                return label
            }
        }
        return nil
    }
    
    func dateSelection(_ selection: UICalendarSelectionSingleDate, didSelectDate dateComponents: DateComponents?) {
        selection.setSelected(dateComponents, animated: true)
            selectedDate = dateComponents
            reloadDateView(date: Calendar.current.date(from: dateComponents!))
        }
    
}

UICalendarSeclection

캘린더에서 사용자가 단일 날짜, 여러 날짜를 선택하거나 날짜를 선택하지 않도록 할 수 있다.

 

UICalendarSelectionSingleDateDelegate

선택 가능한 날짜를 제공하고 단일 날짜 선택에 대한 변경 사항을 처리하기 위해 구현하는 메서드

각각의 메서드에 조건을 걸어 캘린더 내 일자를 선택했을 때 강아지 이모지가 나타나도록 구현했다.

그 이후 다시 일자를 누르면 강아지 이모지가 없어지도록 구현하고 싶었으나 나름 알맞는 코드를 넣었다고 생각해도 제대로 구현되지 않아 거기까지는 하지 못했다.

다음에 기능을 추가할 때 살짝 변형해서 TodoList 일자에 이벤트가 있다면 캘린더에 그 부분이 표시될 수 있도록 구현할 예정이다.

 

출처 : https://ohwhatisthis.tistory.com/23