이용한 라이브러리 : FSCalendar
https://github.com/WenchaoD/FSCalendar
var calendar = FSCalendar() // 인스턴스 생성
func settingCalendar() {
// 커스텀 셀 등록 (CalendarCell 클래스는 밑에서 구현)
calendar.register(CalendarCell.self, forCellReuseIdentifier: CalendarCell.description())
// 프로토콜 연결
calendar.delegate = self
calendar.dataSource = self
// 초기 날짜 지정
calendar.setCurrentPage(Date(), animated: true)
calendar.select(Date())
// 기존의 헤더 가림 -> 커스텀 헤더뷰 디자인 예정
calendar.appearance.headerTitleColor = .clear
calendar.appearance.headerMinimumDissolvedAlpha = 0.0
calendar.headerHeight = 66
// 각종 설정
calendar.today = nil
calendar.scrollDirection = .horizontal
calendar.locale = Locale.init(identifier: "en")
calendar.scope = .month
calendar.translatesAutoresizingMaskIntoConstraints = false
calendar.appearance.titleSelectionColor = .lightGray.withAlphaComponent(0.5)
calendar.appearance.selectionColor = .clear
calendar.appearance.weekdayFont = .boldSystemFont(ofSize: 14)
calendar.appearance.caseOptions = .weekdayUsesSingleUpperCase
calendar.appearance.weekdayTextColor = .black
calendar.appearance.titleFont = .boldSystemFont(ofSize: 12)
calendar.weekdayHeight = 10
calendar.placeholderType = .none
}
class CalendarCell: FSCalendarCell {
// 뒤에 표시될 이미지
var backImageView = {
let view = UIImageView()
view.contentMode = .scaleAspectFill
view.clipsToBounds = true
return view
}()
override init(frame: CGRect) {
super.init(frame: frame)
// 날짜 텍스트가 디폴트로 약간 위로 올라가 있어서, 아예 레이아웃을 잡아준다
self.titleLabel.snp.makeConstraints { make in
make.center.equalTo(contentView)
}
contentView.insertSubview(backImageView, at: 0)
backImageView.snp.makeConstraints { make in
make.center.equalTo(contentView)
make.size.equalTo(minSize())
}
backImageView.layer.cornerRadius = minSize()/2
}
required init(coder aDecoder: NSCoder!) {
fatalError("init(coder:) has not been implemented")
}
override func layoutSubviews() {
super.layoutSubviews()
}
override func prepareForReuse() {
super.prepareForReuse()
backImageView.image = nil
}
// 셀의 높이와 너비 중 작은 값을 리턴한다
func minSize() -> CGFloat {
let width = contentView.bounds.width - 5
let height = contentView.bounds.height - 5
return (width > height) ? height : width
}
}
extension MonthCalendarViewController: FSCalendarDelegate, FSCalendarDataSource {
// 오늘 이후의 날짜는 선택이 불가능하다
func maximumDate(for calendar: FSCalendar) -> Date {
return Date()
}
func calendar(_ calendar: FSCalendar, cellFor date: Date, at position: FSCalendarMonthPosition) -> FSCalendarCell {
guard let cell = calendar.dequeueReusableCell(withIdentifier: CalendarCell.description(), for: date, at: position) as? CalendarCell else { return FSCalendarCell() }
// (viewModel) url을 받아서, 배경 이미지를 띄워준다
viewModel.fetchArtwork(date) { url in
cell.backImageView.kf.setImage(with: url)
print(date)
}
// 현재 선택되어 있는 날짜인지 확인 후 배경 이미지의 alpha값을 조절한다
cell.backImageView.alpha = viewModel.isCurrentSelected(date) ? 1 : 0.5
return cell
}
func calendar(_ calendar: FSCalendar, didSelect date: Date, at monthPosition: FSCalendarMonthPosition) {
// (viewModel) 현재 선택된 날짜 업데이트
viewModel.updateSelectedDate(date)
// 기존에 선택했던 날짜의 셀 배경의 alpha값을 다시 0.5로 바꿔주고,
// 새롭게 선택한 날짜의 셀 배경의 alpha값을 1로 바꿔준다
if let previousCell = calendar.cell(for: viewModel.previousSelectedDate.value, at: monthPosition) as? CalendarCell {
previousCell.backImageView.alpha = 0.5
}
if let currentCell = calendar.cell(for: viewModel.currentSelectedDate.value, at: monthPosition) as? CalendarCell {
currentCell.backImageView.alpha = 1
}
}
func calendarCurrentPageDidChange(_ calendar: FSCalendar) {
// 캘린더를 스와이프해서 이전/다음 달로 넘길 때,
// 타이틀뷰에 있는 레이블 값을 바꿔준다 (October)
currentPageDate = calendar.currentPage
monthView.headerLabel.text = Constant.DateFormat.headerDateFormatter.string(from: currentPageDate)
calendar.reloadData()
}
}
calendar.reloadData()
를 실행시키면
꿀팁공유해주셔서 감사해요
이미지 넣는거 참고하고 갑니다!!
복받으세요