티스토리 뷰
달력 뷰 미리 보기
Calendar
구조체도 알아봤으니 이제 달력 구현을 위하여 뷰를 구성해 보겠습니다.
위의 사진과 같은 심플한 달력을 만들 겁니다.
각각 뭐하는 친구들인지 설명도 적어드릴게요!
titleLabel
:2022년 01
월과 같이 년, 월 정보를 보여줍니다.previousButton
: 이전 달로 이동하는 버튼입니다.nextButton
: 다음 달로 이동하는 버튼입니다.todayButton
: 현재 달로 이동합니다.weekStackView
: 일요일부터 토요일까지 요일을 보여줍니다.collectionView
: 1일부터 날짜를 보여줍니다.
달력 뷰 구성하기
프로젝트 생성 및 초기 설정
iOS App으로 프로젝트를 생성하겠습니다.
Product Name에 원하는 앱 이름을 적어주세요.
저는 스토리보드 없이 코드로만 작성할 거라서 스토리보드를 삭제했습니다.
스토리보드 없이 뷰 컨트롤러 연결하는 방법은 여기에서 확인해주세요!
import UIKit
final class ViewController: UIViewController {
private lazy var scrollView = UIScrollView()
private lazy var contentView = UIView()
private lazy var titleLabel = UILabel()
private lazy var previousButton = UIButton()
private lazy var nextButton = UIButton()
private lazy var todayButton = UIButton()
private lazy var weekStackView = UIStackView()
private lazy var collectionView = UICollectionView(frame: .zero, collectionViewLayout: UICollectionViewFlowLayout())
ViewController
에 필요한 프로퍼티를 생성해줍니다.
작은 화면에서도 잘리지 않고 잘 보였으면 해서 UIScrollView
도 생성해줬습니다.
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = .systemBackground
self.configure()
}
private func configure() {
self.configureScrollView()
self.configureContentView()
self.configureTitleLabel()
}
private func configureScrollView() {
}
private func configureContentView() {
}
private func configureTitleLabel() {
}
viewDidLoad()
에서 뷰의 색상을 .systemBackground
로 바꿔주고, 설정 메서드를 모아 놓은 메서드인 configure()
를 불러주겠습니다.configure()
에서는 scrollView
, contentView
, titleLabel
을 설정해 주는 메서드를 불러주세요.
private func configureScrollView() {
self.view.addSubview(self.scrollView)
self.scrollView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
self.scrollView.topAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.topAnchor),
self.scrollView.leadingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.leadingAnchor),
self.scrollView.trailingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.trailingAnchor),
self.scrollView.bottomAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.bottomAnchor)
])
}
private func configureContentView() {
self.scrollView.addSubview(self.contentView)
self.contentView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
self.contentView.topAnchor.constraint(equalTo: self.scrollView.topAnchor),
self.contentView.leadingAnchor.constraint(equalTo: self.scrollView.leadingAnchor),
self.contentView.trailingAnchor.constraint(equalTo: self.scrollView.trailingAnchor),
self.contentView.bottomAnchor.constraint(equalTo: self.scrollView.bottomAnchor),
self.contentView.widthAnchor.constraint(equalTo: self.scrollView.widthAnchor)
])
}
self.view
에 scrollView
를 넣고 scrollView
에 contentView
를 넣어주었습니다.
위아래로만 스크롤할 거니 contentView
의 width
를 scrollView
의 width
와 같게 제약사항을 줍니다.
이제 이 contentView
에 타이틀, 요일 스택 뷰, 달력 등을 넣어주면 됩니다.
년, 월 타이틀
private func configureTitleLabel() {
self.contentView.addSubview(self.titleLabel)
self.titleLabel.text = "2000년 01월"
self.titleLabel.font = .monospacedSystemFont(ofSize: 18, weight: .bold)
self.titleLabel.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
self.titleLabel.topAnchor.constraint(equalTo: self.contentView.topAnchor, constant: 20),
self.titleLabel.centerXAnchor.constraint(equalTo: self.contentView.centerXAnchor)
])
}
contentView
에 titleLabel
을 넣고 텍스트, 폰트 설정을 주고 상단에서 20 떨어진 위치 중앙에 배치를 해줍니다.
그 후 실행해 보면 위와 같은 화면을 확인할 수 있습니다.
버튼
이전 달, 다음 달, 이번 달로 이동하는 버튼을 설정해주겠습니다.
private func configure() {
self.configureScrollView()
self.configureContentView()
self.configureTitleLabel()
self.configurePreviousButton()
self.configureNextButton()
self.configureTodayButton()
}
설정 메서드를 만들어주고 configure()
에서 불러줍니다.
앞으로 만드는 메서드들은 생성 후 모두 configure()
에서 불러주면 됩니다!
private func configurePreviousButton() {
self.contentView.addSubview(self.previousButton)
self.previousButton.tintColor = .label
self.previousButton.setImage(UIImage(systemName: "chevron.left"), for: .normal)
self.previousButton.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
self.previousButton.widthAnchor.constraint(equalToConstant: 44),
self.previousButton.heightAnchor.constraint(equalToConstant: 44),
self.previousButton.trailingAnchor.constraint(equalTo: self.titleLabel.leadingAnchor, constant: -5),
self.previousButton.centerYAnchor.constraint(equalTo: self.titleLabel.centerYAnchor)
])
}
private func configureNextButton() {
self.contentView.addSubview(self.nextButton)
self.nextButton.tintColor = .label
self.nextButton.setImage(UIImage(systemName: "chevron.right"), for: .normal)
self.nextButton.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
self.nextButton.widthAnchor.constraint(equalToConstant: 44),
self.nextButton.heightAnchor.constraint(equalToConstant: 44),
self.nextButton.leadingAnchor.constraint(equalTo: self.titleLabel.trailingAnchor, constant: 5),
self.nextButton.centerYAnchor.constraint(equalTo: self.titleLabel.centerYAnchor)
])
}
똑같이 contentView
에 넣어주고 색상, 이미지, 제약 사항을 설정해줍니다.
private func configureTodayButton() {
self.contentView.addSubview(self.todayButton)
self.todayButton.setTitle("Today", for: .normal)
self.todayButton.setTitleColor(.systemBackground, for: .normal)
self.todayButton.backgroundColor = .label
self.todayButton.layer.cornerRadius = 5
self.todayButton.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
self.todayButton.widthAnchor.constraint(equalToConstant: 60),
self.todayButton.heightAnchor.constraint(equalToConstant: 30),
self.todayButton.trailingAnchor.constraint(equalTo: self.contentView.trailingAnchor, constant: -10),
self.todayButton.centerYAnchor.constraint(equalTo: self.titleLabel.centerYAnchor)
])
}
이번 달로 이동하는 버튼은 타이틀과 배경색을 모두 설정해주었습니다.
약간 둥근 사각형을 만들고 싶어서 cornerRadius
를 5로 주었습니다.
위치는 contentView.trailing
에서 -10 떨어진 위치에 todayButton.trailing
이 오게 설정해주었습니다.
버튼 설정이 끝났습니다.
요일 스택 뷰
private func configureWeekStackView() {
self.contentView.addSubview(self.weekStackView)
self.weekStackView.distribution = .fillEqually
self.weekStackView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
self.weekStackView.topAnchor.constraint(equalTo: self.titleLabel.bottomAnchor, constant: 40),
self.weekStackView.leadingAnchor.constraint(equalTo: self.contentView.leadingAnchor, constant: 5),
self.weekStackView.trailingAnchor.constraint(equalTo: self.contentView.trailingAnchor, constant: -5)
])
}
weekStackView
의 distribution을 .fillEqually
로 설정하여 스택 뷰에 들어가는 아이템이 모두 같은 크기를 가지게 해 줍니다.
스택 뷰 설정이 끝났으니 아래에서 스택 뷰에 들어갈 아이템을 생성해주겠습니다.
private func configureWeekLabel() {
let dayOfTheWeek = ["일", "월", "화", "수", "목", "금", "토"]
for i in 0..<7 {
let label = UILabel()
label.text = dayOfTheWeek[i]
label.textAlignment = .center
self.weekStackView.addArrangedSubview(label)
if i == 0 {
label.textColor = .systemRed
} else if i == 6 {
label.textColor = .systemBlue
}
}
}
배열에 요일을 넣어 준 후 for
문을 돌며 UILabel
을 만들어 weekStackView
에 넣어줍니다.
요일 스택 뷰 설정도 끝났습니다!
달력 컬렉션 뷰
이제 진짜 마지막입니다.
가장 중요한 collectionView
설정만 해주면 끝입니다!
커스텀 셀을 위하여 새로운 파일을 만들어줍니다.
Cocoa Touch Class를 선택해 준 후 Class이름을 설정해주세요.
static let identifier = "CalendarCollectionViewCell"
private lazy var dayLabel = UILabel()
CalendarCollectionViewCell
에 identifier
와 dayLabel
을 추가해 줍니다.
required init?(coder: NSCoder) {
super.init(coder: coder)
self.configure()
}
override init(frame: CGRect) {
super.init(frame: frame)
self.configure()
}
private func configure() {
self.addSubview(self.dayLabel)
self.dayLabel.text = "0"
self.dayLabel.font = .boldSystemFont(ofSize: 12)
self.dayLabel.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
self.dayLabel.topAnchor.constraint(equalTo: self.topAnchor, constant: 5),
self.dayLabel.centerXAnchor.constraint(equalTo: self.centerXAnchor)
])
}
required init?(coder: NSCoder)
과 override init(frame: CGRect)
에서 configure()
를 불러줍니다.
잘 보이는지 확인하기 위해 텍스트를 "0"
으로 설정해줬습니다.
다시 ViewController
로 돌아가겠습니다.
private func configureCollectionView() {
self.contentView.addSubview(self.collectionView)
self.collectionView.dataSource = self
self.collectionView.delegate = self
self.collectionView.register(CalendarCollectionViewCell.self, forCellWithReuseIdentifier: CalendarCollectionViewCell.identifier)
self.collectionView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
self.collectionView.topAnchor.constraint(equalTo: self.weekStackView.bottomAnchor, constant: 10),
self.collectionView.leadingAnchor.constraint(equalTo: self.weekStackView.leadingAnchor),
self.collectionView.trailingAnchor.constraint(equalTo: self.weekStackView.trailingAnchor),
self.collectionView.heightAnchor.constraint(equalTo: self.collectionView.widthAnchor, multiplier: 1.5),
self.collectionView.bottomAnchor.constraint(equalTo: self.contentView.bottomAnchor)
])
}
collectionView
를 설정해주는 메서드를 생성한 후 collectionView
의 dataSource
와 delegate
를 self
로 설정해줍니다.
아까 생성한 커스텀 셀을 넣어주기 위해서 register
도 해줍니다.
extension ViewController: UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
}
ViewController
에서 UICollectionView
설정에 필요한 프로토콜 세 가지를 채택합니다.
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 42
}
테스트용으로 42개의 셀을 생성해주겠습니다.
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: CalendarCollectionViewCell.identifier, for: indexPath) as? CalendarCollectionViewCell else { return UICollectionViewCell() }
return cell
}
아까 만들어준 커스텀 셀을 collectionView
에 넣어주도록 설정합니다.
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let width = self.weekStackView.frame.width / 7
return CGSize(width: width, height: width * 1.3)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return .zero
}
셀의 크기와 간격을 위와 같이 설정해줍니다.
실행시켜 보면 위와 같은 화면을 만날 수 있습니다.
달력 뷰 구성이 끝났습니다!
다음부터 만들어진 뷰로 본격적인 달력 구현에 들어가겠습니다!
'iOS' 카테고리의 다른 글
[iOS] Calendar 구조체로 달력 구현하기 (4) - 달력 표시, 버튼 기능 구현하기 (2) | 2022.01.05 |
---|---|
[iOS] Calendar 구조체로 달력 구현하기 (3) - 메서드 구현하기 (2) | 2022.01.04 |
[iOS] Calendar 구조체로 달력 구현하기 (1) - Calendar 구조체 알아보기 (2) | 2021.12.11 |
[iOS] Storyboard 없이 ViewController 연결하기 (0) | 2021.07.09 |
[iOS] UIViewController Life Cycle (1) | 2021.07.08 |
- Total
- Today
- Yesterday
- 최대공약수
- TIL
- iTunes Search API
- 프로그래머스
- ternary
- 깊이 우선 탐색
- 별졈
- BOJ
- sql
- Baekjoon
- 유클리드 호제법
- 에로토스테네스의 체
- Firebase
- 최소공배수
- map
- DFS
- calendar
- SWIFT
- programmers
- IOS
- java
- 달력
- Git
- mysql
- 다리를 지나는 트럭
- compactMap
- abs()
- Algorithm
- UISearchController
- Kakao
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |