Swift

iOS Custom Calender 구현하기

Thor_yeom 2023. 4. 17. 22:13

Uikit으로 돌아왔습니다.

이번에는 라이브러리를 사용하지 않고 CustomCalendar를 구현해보도록 하겠습니다.

 

 

 

 

완성본

 

 

1) 최상단에 있는 View를 먼저 구현해보겠습니다.

최상단은 button, title, button button으로 구성되어있습니다. 

class CustomCalendarViewController: UIViewController {
    
    
    // MARK: - Properties

    
    // MARK: - 년, 월 ( 메인 타이틀 )
    var titleLabel: UILabel = {
        let title = UILabel()
        title.font = UIFont.systemFont(ofSize: 15, weight: .semibold)
        title.text = "2023년 01월"
        title.textColor = .label
        return title
    }()
    
    
    // MARK: - 이전 달, 다음달로 이동 버튼
    var previousButton: UIButton = {
        let button = UIButton(type: .system)
        button.setImage(UIImage(systemName: "chevron.left"), for: .normal)
        button.setTitleColor(.label, for: .normal)
        return button
    }()
    
    var nextButton: UIButton = {
        let button = UIButton(type: .system)
        button.setImage(UIImage(systemName: "chevron.right"), for: .normal)
        button.setTitleColor(.label, for: .normal)
        return button
    }()
    
    
    // MARK: - today 버튼
    var todayButton: UIButton = {
        let button = UIButton(type: .system)
        button.setTitle("Today", for: .normal)
        button.backgroundColor = .black
        button.tintColor = .white
        button.layer.cornerRadius = 8
        button.clipsToBounds = true
        return button
    }()
    


    // MARK: - LifeCycle
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .white
        configure()
    }
    
    func configure() {
        configureTitleLabel()
        configurePreviousButton()
        configureNextButton()
        configureTodayButton()
        configureStackView()
        configureCollectionView()
    }
    
    // MARK: - Title 레이아웃
    func configureTitleLabel() {
        view.addSubview(titleLabel)
        titleLabel.translatesAutoresizingMaskIntoConstraints = false
        
        NSLayoutConstraint.activate([
            titleLabel.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 10),
            titleLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor)
        ])
    }
    
    func configurePreviousButton() {
        view.addSubview(previousButton)
        previousButton.translatesAutoresizingMaskIntoConstraints = false
        
        NSLayoutConstraint.activate([
            previousButton.trailingAnchor.constraint(equalTo: titleLabel.leadingAnchor, constant: -10),
            previousButton.centerYAnchor.constraint(equalTo: titleLabel.centerYAnchor),
            previousButton.heightAnchor.constraint(equalToConstant: 44),
            previousButton.widthAnchor.constraint(equalToConstant: 44)
        ])
    }
    
    func configureNextButton() {
        view.addSubview(nextButton)
        nextButton.translatesAutoresizingMaskIntoConstraints = false

        NSLayoutConstraint.activate([
            nextButton.leadingAnchor.constraint(equalTo: titleLabel.trailingAnchor, constant: 10),
            nextButton.centerYAnchor.constraint(equalTo: titleLabel.centerYAnchor),
            nextButton.heightAnchor.constraint(equalToConstant: 44),
            nextButton.widthAnchor.constraint(equalToConstant: 44)
        ])
    }
    
    func configureTodayButton() {
        view.addSubview(todayButton)
        todayButton.translatesAutoresizingMaskIntoConstraints = false
        
        NSLayoutConstraint.activate([
            todayButton.centerYAnchor.constraint(equalTo: titleLabel.centerYAnchor),
            todayButton.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -10),
            todayButton.widthAnchor.constraint(equalToConstant: 70)
        ])
    }
    
    func configureStackView() {
        
    }
    
    func configureCollectionView() {
        
    }
    
    
    
}

 

인스턴스를 클로저를 활용하여 생성해주고 상단의 부분의 레이아웃을 맞추면 됩니다.

configure()안에 함수를 넣어서 정리했습니다.

참 쉽죠?

 

2) 그 아래 요일들을 만들어줍니다

    // MARK: - 요일 Label
    var monLabel: UILabel = {
        let title = UILabel()
        title.text = "월"
        title.textAlignment = .center
        title.font = UIFont.systemFont(ofSize: 12)
        return title
    }()
    
    var tusLabel: UILabel = {
        let title = UILabel()
        title.text = "화"
        title.textAlignment = .center
        title.font = UIFont.systemFont(ofSize: 12)
        return title
    }()
    
    var wedLabel: UILabel = {
        let title = UILabel()
        title.text = "수"
        title.textAlignment = .center
        title.font = UIFont.systemFont(ofSize: 12)
        return title
    }()
    
    var thsLabel: UILabel = {
        let title = UILabel()
        title.text = "목"
        title.textAlignment = .center
        title.font = UIFont.systemFont(ofSize: 12)
        return title
    }()
    
    var friLabel: UILabel = {
        let title = UILabel()
        title.text = "금"
        title.textAlignment = .center
        title.font = UIFont.systemFont(ofSize: 12)
        return title
    }()
    
    var satLabel: UILabel = {
        let title = UILabel()
        title.text = "토"
        title.textAlignment = .center
        title.font = UIFont.systemFont(ofSize: 12)
        return title
    }()
    
    var sunLabel: UILabel = {
        let title = UILabel()
        title.text = "일"
        title.textAlignment = .center
        title.font = UIFont.systemFont(ofSize: 12)
        return title
    }()

codebase의 장점이 여기서 들어납니다... 바로 개발자들에게 뗄래야 뗄 수 없는 복붙...



3) Label들을 하나씩 레이아웃 맞추는 것보다 StackView를 활용해서 맞춰줍니다.

    // MARK: - StackView
    lazy var weekStackView: UIStackView = {
        let stackView = UIStackView(arrangedSubviews: [sunLabel, monLabel, tusLabel, wedLabel, thsLabel, friLabel, satLabel])
        stackView.axis = .horizontal
        stackView.distribution = .fillEqually
        return stackView
    }()

자 여기서 보면 var 앞에 lazy가 붙었는데 왜 붙었을까요? 

lazy를 붙이면 장점이 있는데, 자세한건 추후에 포스팅 하겠습니다... 요게 MZ밀당 맞나요? ㅎㅎ 

 

쉽게 말씀드리면 순서에 차이를 둔다 고 보시면 됩니다. 

메모리가 호출되면 그때 값을 초기화시킵니다.

그냥 var로 선언하고 StackView를 만들게 되면 비어있는 StackView와 

Label가 동시에 올라가기 때문에 Error가 발생합니다.

 

 

4) 자 이렇게 StackView까지 만들었으면 레이아웃을 잡아 줍니다.

    func configureStackView() {
        view.addSubview(weekStackView)
        weekStackView.translatesAutoresizingMaskIntoConstraints = false
        
        NSLayoutConstraint.activate([
            weekStackView.leadingAnchor
            weekStackView.topAnchor
            weekStackView.trailingAnchor
        ])
    }

전 이렇게 먼저 앵커를 걸어둘곳을 먼저 생각하고 나머지를 완성시킵니다.

제 개인취향이니 존중해주시와요 ㅠ

    func configureStackView() {
        view.addSubview(weekStackView)
        weekStackView.translatesAutoresizingMaskIntoConstraints = false
        
        NSLayoutConstraint.activate([
            weekStackView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 10),
            weekStackView.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 40),
            weekStackView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -10)
        ])
    }

 

현재까지 완성 사진입니다. 흠.. 나쁘지 않네요! 좋네요 

그럼 여기서 끊고 다음에 또 만나요! 모두 화이팅 하세요!

 

 

참고 블로그

https://boreum.tistory.com/63

 

[iOS] Calendar 구조체로 달력 구현하기 (2) - 달력 뷰 구성하기

달력 뷰 미리 보기 Calendar 구조체도 알아봤으니 이제 달력 구현을 위하여 뷰를 구성해 보겠습니다. 위의 사진과 같은 심플한 달력을 만들 겁니다. 각각 뭐하는 친구들인지 설명도 적어드릴게요!

boreum.tistory.com

 

'Swift' 카테고리의 다른 글

iOS Custom Calendar 구현하기 3  (2) 2023.04.18
iOS Custom Calendar 구현하기2  (0) 2023.04.17
어서와 SwiftUI @FetchRequest는 처음이지?  (0) 2023.03.23
SwiftUI @AppStorage 심화편  (0) 2023.03.22
SwiftUI OpenAPI 적용시키기  (0) 2023.02.14