Objective-C 및 Swift와 호환되는 커스텀이 가능한 캘린더 라이브러리
FSCalendar Cheat sheet
주의사항
- FSCalendarView의 appearance로 설정한 값들은 FSCalendarDelegateAppearance의 메서드보다 우선순위가 낮습니다.
- FSCalendarDelegateAppearance 메서드를 사용하는 경우 채택하고 있는지 확인
import UIKit
import FSCalendar
final class ViewController: UIViewController {
// MARK: - UI
private lazy var calendarWrapView: UIView = {
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(calendar)
return view
}()
private lazy var calendar: FSCalendar = {
let calendar = FSCalendar()
calendar.translatesAutoresizingMaskIntoConstraints = false
return calendar
}()
private var dateFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd"
return formatter
}()
private var today = Date()
private lazy var eightDaysLater = Calendar.current.date(byAdding: .day, value: +8, to: self.today)
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemBackground
self.view.addSubview(calendarWrapView)
NSLayoutConstraint.activate([
calendarWrapView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
calendarWrapView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20),
calendarWrapView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20),
calendarWrapView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor),
calendar.topAnchor.constraint(equalTo: calendarWrapView.topAnchor),
calendar.leadingAnchor.constraint(equalTo: calendarWrapView.leadingAnchor),
calendar.trailingAnchor.constraint(equalTo: calendarWrapView.trailingAnchor),
calendar.bottomAnchor.constraint(equalTo: calendarWrapView.bottomAnchor)
])
self.configureCalendar()
}
private func configureCalendar() {
// MARK: - 기본 설정
// FSCalendarDelegate 설정
self.calendar.delegate = self
// FSCalendarDataSource 설정
self.calendar.dataSource = self
// Locale 설정 - 🚨 한국으로 설정시 자동으로 상단요일 텍스트가 일~월로 표시됨
self.calendar.locale = Locale(identifier: "ko_KR")
// cornerRadius
self.calendar.layer.cornerRadius = 8
// 달력 스크린 가능여부
self.calendar.scrollEnabled = true
// 달력 스크린 방향
self.calendar.scrollDirection = .horizontal
// 달력 범위 - .week(주간), .month(월간)
self.calendar.scope = .month
// MARK: - 상단 요일
// 상단 요일 - 폰트, 사이즈 변경 - 🚨 텍스트변경이후에 호출하면 Default영어로 변경됨
self.calendar.appearance.weekdayFont = UIFont.systemFont(ofSize: 20, weight: .semibold)
// 상단 요일 - 텍스트 변경
/*
self.calendar.calendarWeekdayView.weekdayLabels[0].text = "일"
self.calendar.calendarWeekdayView.weekdayLabels[1].text = "월"
self.calendar.calendarWeekdayView.weekdayLabels[2].text = "화"
self.calendar.calendarWeekdayView.weekdayLabels[3].text = "수"
self.calendar.calendarWeekdayView.weekdayLabels[4].text = "목"
self.calendar.calendarWeekdayView.weekdayLabels[5].text = "금"
self.calendar.calendarWeekdayView.weekdayLabels[6].text = "토"
*/
// 상단 요일 - 요약옵션 - 🚨 영어인 경우 동작함 (.weekdayUsesUpperCase: 대문자3글자, headerUsesCapitalized, headerUsesUpperCase: 첫글자 대문자인 3글자, weekdayUsesSingleUpperCase: 한글자)
// self.calendar.appearance.caseOptions = .headerUsesCapitalized
// 상단 요일 - 글자색
self.calendar.appearance.weekdayTextColor = .systemYellow
// MARK: - 숫자
// 숫자 - 폰트, 사이즈 변경
self.calendar.appearance.titleFont = UIFont.systemFont(ofSize: 20, weight: .semibold)
// 숫자 - 해당 월이 아닌 날짜의 색 지정
self.calendar.appearance.titlePlaceholderColor = .systemBlue
// 숫자 - 해당 월이 아닌 날짜 표시 옵션 - (fillSixRows: 6줄, fillHeadTail: 보이는 기준, none: 제거)
self.calendar.placeholderType = .fillSixRows
// 숫자 - 해당 월인 날짜 색
self.calendar.appearance.titleDefaultColor = .systemGreen
// 숫자 - 현재 날짜 원 색상 - 🚨 현재 날짜가 선택된 경우는 선택한 원 색상의 우선순위가 높음
self.calendar.appearance.todayColor = .red
// 숫자 - 현재 날짜 텍스트 색상 - 🚨 현재 날짜가 선택된 경우는 선택한 텍스트 색상의 우선순위가 높음
self.calendar.appearance.titleTodayColor = .blue
// 숫자 - 선택한 원 색상
self.calendar.appearance.selectionColor = .black
// 숫자 - 선택한 텍스트 색상
self.calendar.appearance.titleSelectionColor = .green
// 숫자 - subtitle간의 간격 조정
self.calendar.appearance.subtitleOffset = CGPoint(x: 4, y: 2)
// MARK: - 헤더
// Header - DateFormat
self.calendar.appearance.headerDateFormat = "yy년 MM월"
// Header - 높이
self.calendar.headerHeight = 60
// Header - 양 옆 년도 월 투명도 - 🚨 스크롤방향이 horizontal인 경우만 표시됨
self.calendar.appearance.headerMinimumDissolvedAlpha = 1.0
// Header Title - 폰트
self.calendar.appearance.headerTitleFont = .systemFont(ofSize: 10, weight: .light)
// Header Title - 색상
self.calendar.appearance.headerTitleColor = .systemRed
// Header Title - 방향
self.calendar.appearance.headerTitleAlignment = .center
// MARK: - Etc
// 캘린더 선택 처리
self.calendar.select(self.today)
// 이벤트 - 기본 색상
self.calendar.appearance.eventDefaultColor = UIColor.green
// 이벤트 - 선택 색상
self.calendar.appearance.eventSelectionColor = UIColor.red
// 이벤트 - 간격
self.calendar.appearance.eventOffset = CGPoint(x: 10, y: -7)
// 다중 선택 가능여부
self.calendar.allowsMultipleSelection = true
// Swipe로 선택 가능여부
self.calendar.swipeToChooseGesture.isEnabled = false
}
}
// MARK: - FSCalendarDelegateAppearance, FSCalendarDataSource (FSCalendarDelegateAppearance가 FSCalendarDelegate를 채택 중
extension ViewController: FSCalendarDelegateAppearance, FSCalendarDataSource {
// 날짜를 선택했을 때 호출
func calendar(_ calendar: FSCalendar, didSelect date: Date, at monthPosition: FSCalendarMonthPosition) {
print("📅 :\\(date) 날짜 선택")
}
// 선택된 날짜를 선택했을 때 호출
func calendar(_ calendar: FSCalendar, didDeselect date: Date, at monthPosition: FSCalendarMonthPosition) {
print("📅 :\\(date) 날짜 선택 해제")
}
// 날짜 선택 직전 호출
func calendar(_ calendar: FSCalendar, shouldSelect date: Date, at monthPosition: FSCalendarMonthPosition) -> Bool {
// 3개 까지는 선택 됨
return (calendar.selectedDates.count > 2) ? false : true
}
// 선택된 날짜의 채워진 색상 지정
func calendar(_ calendar: FSCalendar, appearance: FSCalendarAppearance, fillSelectionColorFor date: Date) -> UIColor? {
return UIColor.systemIndigo
}
// 선택된 날짜 테두리 색상
func calendar(_ calendar: FSCalendar, appearance: FSCalendarAppearance, borderSelectionColorFor date: Date) -> UIColor? {
return UIColor.systemPink
}
// 모든 날짜의 채워진 색상 지정
func calendar(_ calendar: FSCalendar, appearance: FSCalendarAppearance, fillDefaultColorFor date: Date) -> UIColor? {
return UIColor.purple.withAlphaComponent(0.1)
}
// title의 디폴트 색상 - 🚨 사용시 titleDefaultColor와 titlePlaceholderColor 무시됨
func calendar(_ calendar: FSCalendar, appearance: FSCalendarAppearance, titleDefaultColorFor date: Date) -> UIColor? {
let components = Calendar.current.dateComponents([.weekday], from: date)
print("date : \\(date), today : \\(self.today)" )
let isMinimumTarget = (Calendar.current.compare(date, to: self.today, toGranularity: .day) != .orderedAscending)
let isMaximumTarget = (Calendar.current.compare(date, to: self.eightDaysLater!, toGranularity: .day) != .orderedDescending)
let isTarget = isMinimumTarget && isMaximumTarget
switch components.weekday {
case 1:
return .blue.withAlphaComponent(isTarget ? 1.0 : 0.4)
case 7:
return .red.withAlphaComponent(isTarget ? 1.0 : 0.4)
default:
return .black.withAlphaComponent(isTarget ? 1.0 : 0.4)
}
}
// subtitle의 디폴트 색상
func calendar(_ calendar: FSCalendar, appearance: FSCalendarAppearance, subtitleDefaultColorFor date: Date) -> UIColor? {
return UIColor.brown
}
// 원하는 날짜에 subtitle 지정
func calendar(_ calendar: FSCalendar, subtitleFor date: Date) -> String? {
let calendarDateString = dateFormatter.string(from: date)
let todayDateString = dateFormatter.string(from: Date())
if calendarDateString == todayDateString {
return "오늘"
} else {
return "sub"
}
}
// 원하는 날짜에 title 지정
func calendar(_ calendar: FSCalendar, titleFor date: Date) -> String? {
let calendarDateString = dateFormatter.string(from: date)
let todayDateString = dateFormatter.string(from: Date())
if calendarDateString == todayDateString {
return "오늘"
} else {
return nil
}
}
// 이벤트 표시 갯수 - 최대 3
func calendar(_ calendar: FSCalendar, numberOfEventsFor date: Date) -> Int {
return 2
}
// 선택 가능한 최소 날짜
func minimumDate(for calendar: FSCalendar) -> Date {
guard let eightDaysAgo = Calendar.current.date(byAdding: .day, value: -8, to: self.today)
else { return Date()}
return eightDaysAgo
}
// 선택 가능한 최대 날짜
func maximumDate(for calendar: FSCalendar) -> Date {
guard let eightDaysLater = Calendar.current.date(byAdding: .day, value: +8, to: self.today)
else { return Date()}
return eightDaysLater
}
// 페이지 변화에 대한 이벤트 - 스크롤
func calendarCurrentPageDidChange(_ calendar: FSCalendar) {
print("페이지 변환")
}
// 이벤트 위치
func calendar(_ calendar: FSCalendar, appearance: FSCalendarAppearance, eventOffsetFor date: Date) -> CGPoint {
return CGPoint(x: -7, y: -50)
}
// 기본 이벤트 색상 - 배열 순서대로 이벤트 색상 설정
func calendar(_ calendar: FSCalendar, appearance: FSCalendarAppearance, eventDefaultColorsFor date: Date) -> [UIColor]? {
return [UIColor.red]
}
// 선택된 이벤트 색상 - 배열 순서대로 이벤트 색상 설정
func calendar(_ calendar: FSCalendar, appearance: FSCalendarAppearance, eventSelectionColorsFor date: Date) -> [UIColor]? {
return [UIColor.green, UIColor.blue]
}
}
'iOS > 3rd Party Library' 카테고리의 다른 글
[iOS] CocoaPods - 라이브러리 생성 및 배포하기 (4) | 2024.07.23 |
---|---|
[iOS] CocoaPods - 명령어 및 에러 정리 (1) | 2024.07.23 |
[iOS] CocoaPods - 기본설명 (1) | 2024.07.23 |
[iOS] Fastlane Plugin을 활용하여 앱아이콘 Badge 표시 (0) | 2024.07.02 |
[iOS] Atributika 라이브러리 (HTML to NSAttributedString) (0) | 2024.03.20 |