[iOS] 화면 방향에 따른 collectionView cellSize 변경

naljin
5 min readSep 26, 2019

--

부스트코스 iOS 5차 프로젝트 ‘BoxOffice’ 과제에서는 아래와 같이 collectionView 형태로 영화 리스트 보여줘야 한다.

이렇게 세로 화면에서는 줄 당 아이템 2개가 보인다.

그런데 가로화면에서도 같은 비율로 줄 당 아이템 2개 보여준다면?

이상하다.

요구 사항

아이템의 크기가 더 작아지고 줄 당 보여주는 아이템 수가 많아져야 할 것 같다. 이런식으로.

따라서 세로, 가로 모드에 따른 셀 사이즈 조절이 필요하다.

해결 방법

UICollectionViewDelegateFlowLayout 라는 protocol에는 아래와 같은 함수가 속해있다.

해당 함수를 통해 아이템의 셀 사이즈를 직접 지정해줄 수 있다.

CGSize 를 반환하니까 저 함수 안에

return CGSize(width: 100, height: 100)

이런식으로 리턴하면 셀의 가로/세로 사이즈가 각각 100이 된다.

따라서 디바이스의 방향에 따라 return 하는 사이즈를 다르게 하면 되겠다.

UIDevice.current.orientation.isLandscape

위의 식에 따라 현재 디바이스의 상태가 가로 모드인지 세로 모드인지 판단할 수 있다. 이렇게.

참고로 저 안의 getCellSize 함수는 UICollectionView의 extension에 따로 구현한 함수이다. 한 줄에 들어가야할 아이템의 개수와 셀의 비율을 parameter로 넣어주면 적절한 cellSize를 반환한다.

새로운 문제 — 1

아이폰 xr에서는 디바이스 방향을 변경할때마다 collectionView(_:layout:sizeForItemAt:)함수가 매번 불리고 잘 작동했다. 하지만 5s에서 실행할때는 가로모드로 변경될때만 해당 함수가 실행됐다.

따라서 화면을 돌릴때마다 시점을 캐치하고 레이아웃을 다시 그려줘야 했다.

해결 방법 — 1

이 함수는 container에 뷰의 사이즈가 바뀔 것이라고 알려준다.

따라서 디바이스 화면 방향이 바뀔때마다 동작하게 되고, 안에 collectionView의 layout을 업데이트 시켜주는 코드를 넣어주면 된다.

if let flowLayout = self.collectionView!.collectionViewLayout as? UICollectionViewFlowLayout {
flowLayout.invalidateLayout()
}

flowLayout.invalidateLayout()가 그런 기능을 하는데, invalidateLayout 는 현재 layout을 무효화하고 layout 업데이트를 작동시킨다.

새로운 문제 — 2

그런데 다음 화면으로 넘어가서 디바이스 방향을 변경할때도 저 함수가 불리면서 nil 값인 collectionView에 접근하려고 해서 크래시가 났다.

Unexpectedly found nil while implicitly unwrapping an Optional value

다른 뷰에서 디바이스 방향을 변경할때도viewWillTransition(to:with:) 가 불리는게 당황스러웠다.

구글링을 해보니 원래 해당 메소드는 이 메소드를 포함한 ViewController에서만 동작하지만 지금은 네비게이션 컨트롤러 쓰고있기 때문에 그 전의 뷰들이 메모리상에 존재하고 있기 때문에 viewWillTransition(to:with:)가 동작하는 듯 하다.

해결 방법 — 2

다른 레퍼런스들에 의하면 현재 뷰의 방향이 변화할때 각각의 ViewController에 있는 viewWillTransition(to:with:) 가 동작할 적절한 시점인지 판단해서 해결하는 듯 하다.

나는 collectionView를 optional 으로 만들어서 실제 값이 있을때만 동작하도록 처리했다.

if let flowLayout = self.collectionView?.collectionViewLayout as? UICollectionViewFlowLayout {
flowLayout.invalidateLayout()
}

참고 링크

--

--