[CustomView] 커스텀 캘린더뷰 만들기
iOS 16부터 기본 제공되는 캘린더
기본 캘린더
import UIKit
final class BasicCalendarViewController: UIViewController {
// MARK: - UI Conponent
private lazy var calendarView: UICalendarView = {
let view = UICalendarView()
view.translatesAutoresizingMaskIntoConstraints = false
/// 점이나 뱃지 표시 등 달력 Custom 하기 위해 설정해야 하는 속성
view.wantsDateDecorations = true
return view
}()
override func viewDidLoad() {
super.viewDidLoad()
makeUI()
constraints()
}
private func makeUI() {
view.backgroundColor = .white
view.addSubview(calendarView)
}
private func constraints() {
let calendarViewConstraints = [
calendarView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
calendarView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 20),
calendarView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -20)
]
NSLayoutConstraint.activate(calendarViewConstraints)
}
}
UICalendarSelectionSingleDateDelegate를 설정하여 날짜 선택시 이모지 표시
import UIKit
final class BasicCalendarViewController: UIViewController {
/// 현재 선택된 날짜
var selectedDate: DateComponents? = nil
// MARK: - UI Conponent
/// 날짜별 데코레이션(점, 이모지 등)을 지원하는 캘린더 뷰
private lazy var calendarView: UICalendarView = {
let view = UICalendarView()
view.locale = Locale(identifier: "ko_KR")
view.translatesAutoresizingMaskIntoConstraints = false
/// 점이나 뱃지 표시 등 달력 Custom 하기 위해 설정해야 하는 속성
view.wantsDateDecorations = true
return view
}()
override func viewDidLoad() {
super.viewDidLoad()
self.makeUI()
self.constraints()
self.setCalendar()
}
/// 캘린더 delegate 및 날짜 선택 동작 설정
private func setCalendar() {
self.calendarView.delegate = self
/// 한 번에 한 날짜만 선택 가능
let dateSection = UICalendarSelectionSingleDate(delegate: self)
/// 선택 이벤트(날짜 선택 시 콜백)를 BasicCalendarViewController에서 직접 처리하겠다
calendarView.selectionBehavior = dateSection
}
private func makeUI() {
view.backgroundColor = .white
view.addSubview(calendarView)
}
private func constraints() {
let calendarViewConstraints = [
calendarView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
calendarView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 20),
calendarView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -20)
]
NSLayoutConstraint.activate(calendarViewConstraints)
}
/// 특정 날짜 셀만 데코레이션 새로고침(이모지 추가)
private func reloadDateView(date: Date?) {
if date == nil { return }
let calendar = Calendar.current
calendarView.reloadDecorations(forDateComponents: [calendar.dateComponents([.day, .month, .year], from: date!)], animated: true)
}
}
// MARK: - 캘린더 Delegate
extension BasicCalendarViewController: 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 객체에 저장
selection.setSelected(dateComponents, animated: true)
/// selectedDate 프로퍼티를 업데이트
selectedDate = dateComponents
/// 선택한 날짜 셀의 데코레이션만 새로고침(🐶 이모지가 바로 반영되게)
reloadDateView(date: Calendar.current.date(from: dateComponents!))
}
}
참고: 한국어로 설정해도 시뮬레이터에서는 요일이 영어로 보이는 버그가 있다.
커스텀 캘린더
//
// 1. CustomCalendar.swift
// UIComponentTutorial
//
// Created by 김동현 on 6/4/25.
//
import UIKit
import FSCalendar
final class CustomCalendarVC: UIViewController {
// MARK: - UI Component
private lazy var calendarView: FSCalendar = {
let calendar = FSCalendar()
// 첫 열을 월요일로 설정
calendar.firstWeekday = 2
// week 또는 month 가능
calendar.scope = .month
calendar.scrollEnabled = true
calendar.locale = Locale(identifier: "ko_KR")
// 현재 달의 날짜들만 표기하도록 설정
calendar.placeholderType = .none
// 헤더뷰 설정
calendar.headerHeight = 55
calendar.appearance.headerDateFormat = "MM월"
calendar.appearance.headerTitleColor = .black
// 요일 UI 설정
calendar.appearance.weekdayFont = UIFont.systemFont(ofSize: 17, weight: .light)
calendar.appearance.weekdayTextColor = .black
// 날짜별 UI 설정
calendar.appearance.titleTodayColor = .white
calendar.appearance.titleFont = UIFont.systemFont(ofSize: 16, weight: .light)
calendar.appearance.subtitleFont = UIFont.systemFont(ofSize: 10, weight: .light)
calendar.appearance.subtitleTodayColor = .systemYellow
calendar.appearance.todayColor = .gray
// 일요일 라벨의 textColor는 red로 설정
calendar.calendarWeekdayView.weekdayLabels.last!.textColor = .red
return calendar
}()
// MARK: - Life Cycle
override func viewDidLoad() {
super.viewDidLoad()
makeUI()
constraints()
}
// MARK: - UI Setting
private func makeUI() {
view.backgroundColor = .white
view.addSubview(calendarView)
calendarView.translatesAutoresizingMaskIntoConstraints = false
}
private func constraints() {
NSLayoutConstraint.activate([
calendarView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 0),
calendarView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20),
calendarView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20),
calendarView.heightAnchor.constraint(equalToConstant: 500)
])
}
}
#Preview {
CustomCalendarVC()
}
Reference
- https://ohwhatisthis.tistory.com/23
- https://maramincho.tistory.com/106
- https://dongdida.tistory.com/128
- https://velog.io/@xanxnu/iOSSwift-UICalendarView-사용해-보기
- https://lsj8706.tistory.com/4
Leave a comment