본문 바로가기

iOS

[iOS] Calendar (2)

이번주는 캘린더의 UI 그리기 편입니다.

고려해야 할 내용은 주로 

 

1) 매 달 1일이 무슨 요일에 시작하는지

2) 매 달 해당 일수를 어떻게 그려야 하는지

입니다. Xib와 CollectionView로 구성하였습니다. 궁금한 점이나 오류가 있다면 댓글 부탁드립니다!

* Xib : CollectionView, CollectionView Cell.

 

컬렉션뷰와 컬렉션뷰 셀.

 

1)  매달 1일이 무슨 요일에 시작하는지

저번 편에서 언급한 바와 같이, 해당 요일의 인덱스는 .weekday 컴포넌트로,

Calendar.current.component(.weekday, from: Date()) 와 같이 받아올 수 있었습니다. 

리턴형은 Int로, 일요일은 1부터, 토요일은 7이었습니다. 예를 들면 2020-04-01은 4(수요일) 이였습니다.

 

4월은 30일까지밖에 없으므로, 

다음과 같은 뷰를 그려내야 합니다.

4월의 일 수 : 30일

첫주의 일 수 : 4일 (수요일부터 시작)

리턴받는 CollectionView Cell의 개수 : 30일 + 1일 이전의 인덱스 3개 -> 33개

 

 

위와 같은 알고리즘으로 뷰를 그려보았습니다. 

 

2) 매 달, 해당 일 수를 어떻게 그려야 하는지

 

컬렉션뷰의 Item의 개수 리턴은 다음과 같이 받았습니다. 

  func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
       
        return numOfDaysInMonth[currentMonthIndex] + firstWeekDayOfMonth - 1
    }

기존 Month배열에, 첫 주의 Index - 1 (Index가 1부터 시작하기 때문에 -1)

 

4월의 Item 개수는 30일 + (첫 주의 Index 4 - 1) 까지 33을 리턴받게 됩니다.

 

하지만, 33개의 셀을 모두 그려낼 필요는 없습니다. 4월은 30일까지 존재하기 때문에 30개의 Item만 그려내면 됩니다.

cell.isHidden 속성을 이용하였습니다.

 

 

매 달의 IndexPath.item과, 매 달의 첫 주의 Index를 비교합니다. 

4월의 경우, IndexPath.item과 numOfDaysInMonth을 비교합니다. 4월은 수요일부터 시작하므로 리턴은 4(수요일)

 

앞에서부터 3개는 그려낼 필요가 없다는 뜻입니다.

0부터 시작하는 IndexPath는 0,1,2는 버려야 합니다. 3부터 그려내야 하므로

if indexPath.item <= firstWeekDayOfMonth - 2 {
            cell.isHidden = true
            return cell
}

다음과 같이 계산하면 셀의 개수를 알맞게 그려낼 수 있게 됩니다.

 

 

3) Tips

공부하다 보니, 재밌게 뷰를 그릴 수 있는 방법...(?)을 알게 되어서 끄적이려고 합니다. 언젠가 써먹을 수 있을까 해서.

CellForItemAt을 다음과 같이 커스텀할 수 있습니다.

 

원래는

 let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "AnyCell", for: indexPath) as? AnyCell

와 같이 하는 형태에서,,,,

 

 func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = DateCollectionViewCell.cellForCollectionView(collectionView: collectionView, indexPath: indexPath)
        
        ~
}

DateCollectionViewCell (cell이름) .cellForCollectionView (만든 함수)를 쓰더라.

저렇게 사용하면 좋은 점 : Xib를 내 의도대로 사용할 수 있었습니다.

 

 class func cellForCollectionView(collectionView: UICollectionView, indexPath: IndexPath) -> DateCollectionViewCell {
        let kDateCollectionViewCellIdentifier = "kDateCollectionViewCellIdentifier"
        
        collectionView.register(UINib(nibName: "DateCollectionViewCell", bundle: Bundle.main), forCellWithReuseIdentifier: kDateCollectionViewCellIdentifier)
        
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: kDateCollectionViewCellIdentifier, for: indexPath) as! DateCollectionViewCell
        return cell
    }

CollectionViewCell 내부에 다음과 같이 선언 후 사용하면 Xib가 Xib 안에 잘 걸립니다. 

코드는 이전 편 깃헙 링크에 있습니다!

 

달력은 힘든 일이라는걸 알았고, 달력 플젝도 엎어져서 필요 없게 되었지만,

또 실력이 성장했으리라 생각하며,,,

 

 

 

'iOS' 카테고리의 다른 글

[iOS] 화면전환 애니메이션 커스텀하기 - CGAffineTransform, animateTransition [1]  (3) 2020.05.15
[iOS] SideBar  (3) 2020.05.09
[iOS] Calendar (1)  (0) 2020.04.25
[iOS] LinkPresentation  (0) 2020.04.18
[iOS, Crecker] ActionSheet,  (0) 2020.04.11