[Swift] CollectionView 첫 번째 셀을 화면 가운데(중간)에 오게 하기

술술·2024년 10월 11일

TIL

목록 보기
20/21

코드


private lazy var flowLayout: UICollectionViewFlowLayout = {
        let layout = UICollectionViewFlowLayout()
        layout.scrollDirection = .horizontal
        layout.minimumLineSpacing = 5
        layout.itemSize = .init(width: UIScreen.main.bounds.width * 0.3, height: UIScreen.main.bounds.height * 0.1)
        return layout
    }()
    
private lazy var collectionView: UICollectionView = {
        let collectionView = UICollectionView(frame: .zero, collectionViewLayout: flowLayout)
        collectionView.backgroundColor = .clear
        collectionView.contentInsetAdjustmentBehavior = .never  // 이거 해줘야 됨
        collectionView.showsHorizontalScrollIndicator = false
        collectionView.delegate = self
        collectionView.dataSource = self
        collectionView.register(TrackViewCell.self, forCellWithReuseIdentifier: TrackViewCell.identifier)
        return collectionView
    }()
    
override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        let inset = (view.frame.width / 2)
        collectionView.contentInset = UIEdgeInsets(top: 0, left: inset, bottom: 0, right: inset)
    }


contentInsetAdjustmentBehavior

Apple 공식문서

  • safeArea를 고려하여 자동으로 레이아웃을 지정해주도록 하는 옵션
  • 4가지 옵션
    • automatic - 인셋을 자동으로 조정
    • scrollableAxes - 스크롤 가능한 방향으로만 인셋을 조정
    • never - 인셋을 조정하지 않음
    • always - 항상 safe area 인셋을 포함

viewDidLayoutSubviews()

개발하다 보면 종종 보이는 이 메서드.
무슨 메서드인지 갑자기 너무 궁금해져서 검색을 해봤다. 알아야 할 것 들이 엄청 많았다.
차근차근 정리를 해보겠다.

Apple 공식문서

When the bounds change for a view controller's view, the view adjusts the positions of its subviews and then the system calls this method. However, this method being called does not indicate that the individual layouts of the view's subviews have been adjusted. Each subview is responsible for adjusting its own layout.
Your view controller can override this method to make changes after the view lays out its subviews. The default implementation of this method does nothing.

뷰 컨트롤러의 뷰에 대한 경계가 변경되면 뷰는 하위 뷰의 위치를 ​​조정한 다음 시스템에서 이 메서드를 호출합니다. 그러나 이 메서드가 호출되었다고 해서 뷰의 하위 뷰의 개별 레이아웃이 조정되었다는 것을 나타내는 것은 아닙니다. 각 하위 뷰는 자체 레이아웃을 조정해야 합니다.
뷰 컨트롤러는 이 메서드를 재정의하여 뷰가 하위 뷰를 레이아웃한 후에 변경할 수 있습니다. 이 메서드의 기본 구현은 아무 작업도 수행하지 않습니다.

자, 하나도 모르겠죠?
여러 블로그 글을 읽으며 대충 이해했지만 사람들은 이런 것들을 어디서 찾아내는 건지 궁금해서 공식 문서를 뒤져봤다.

그 중 도움이 되었던 글은 이것.

Displaying and managing views with a view controller - Prepare your views to appear onscreen

화면에 뷰 컨트롤러를 표시할 때 UIKit은 먼저 해당 뷰를 로드하고 구성해야 하며, 이는 다음 단계 시퀀스를 사용하여 수행합니다.

  1. 뷰의 init(coder:) 메서드를 사용하여 각 뷰를 만듭니다.
  2. 뷰를 뷰 컨트롤러의 해당 액션 및 아웃렛에 연결합니다.
  3. 각 뷰와 뷰 컨트롤러의 awakeFromNib() 메서드를 호출합니다.
  4. 뷰 계층을 뷰 컨트롤러의 뷰 속성에 할당합니다.
  5. 뷰 컨트롤러의 viewDidLoad() 메서드를 호출합니다.

로드 타임에는 뷰 컨트롤러를 사용할 수 있도록 준비하는 데 필요한 일회성 구성 단계만 수행합니다. 로드 타임을 사용하여 스토리보드에 포함되지 않은 추가 뷰를 만들고 구성합니다. 뷰 컨트롤러가 화면에 나타날 때마다 수행해야 하는 작업을 수행하지 마세요. 예를 들어 애니메이션을 시작하거나 뷰의 값을 업데이트하지 마세요.

뷰가 처음 화면에 나타날 때 뷰와 관련된 최종 작업을 수행합니다. UIKit은 뷰가 화면에 나타날 때 소유 뷰 컨트롤러에 알리고, 다음과 같은 방식으로 현재 환경에 맞게 해당 뷰의 레이아웃을 업데이트합니다.

  1. 전환 시작 시 viewWillAppear(_:)를 호출합니다.
  2. 계층에 뷰를 추가합니다.
  3. 뷰 컨트롤러와 뷰의 특성 컬렉션을 업데이트합니다.
  4. 뷰의 크기와 슈퍼뷰에서의 위치를 ​​포함하여 뷰의 지오메트리를 업데이트합니다. 레이아웃 여백과 안전 영역을 업데이트하고 필요한 경우 viewLayoutMarginsDidChange() 및 viewSafeAreaInsetsDidChange()를 호출합니다.
  5. viewIsAppearing(_:) 메서드를 호출하여 뷰 컨트롤러의 뷰가 화면에 표시되고 있음을 알려줍니다.
  6. viewWillLayoutSubviews() 메서드를 호출합니다.
  7. 뷰 계층의 레이아웃을 업데이트합니다.
  8. viewDidLayoutSubviews() 메서드를 호출합니다.
  9. 뷰를 화면에 표시합니다.
  10. 애니메이션이 완료된 후 뷰 컨트롤러의 viewDidAppear(_:) 메서드를 호출합니다.

뷰 컨트롤러의 viewIsAppearing(_:) 메서드에서 뷰의 콘텐츠를 업데이트합니다. 시스템이 이 메서드를 호출하면 뷰가 뷰 계층에 추가되고 프레임, 경계, 여백 및 인셋이 정의됩니다. 시스템이 viewIsAppearing(:)에 추가하는 콘텐츠는 뷰가 처음 화면에 표시될 때 표시됩니다.
시스템은 뷰가 레이아웃을 수행할 때마다 viewWillLayoutSubviews() 및 viewDidLayoutSubviews() 메서드를 호출합니다. 이는 뷰가 표시되는 동안 언제든지 발생할 수 있습니다. 시스템은 각 모양 전환의 일부로 viewIsAppearing(_:)을 한 번만 호출하므로 이 메서드에서 변경한 내용은 뷰가 레이아웃을 수행할 때마다 반복되지 않습니다.


이제 언제 불리는 메서드인지는 이해를 했다. 그래서 어떻게 쓰이는지 알아봤는데 다른 블로그들에 예제가 잘 정리되어 있었다.
예제는 다른 블로그를 참고하면 좋을 것 같고, 정리를 해보자면

  • viewDidLayoutSubviews는 모든 레이아웃이 모두 정해진 후 호출
  • 서브뷰를 다시 배치해야 하거나, 크기, 위치를 조정하는 작업에서 사용

나는 위의 코드 예시와 같이 컬렉션뷰의 레이아웃이 모두 정해진 후 컬렉션뷰 셀의 위치를 조정하는 데에 사용했다.


Reference

https://blog.naver.com/doctor-kick/222437253619
https://ios-daniel-yang.tistory.com/entry/SwiftTIL-17-viewDidLayoutSubviews-간단-정리

profile
Hello

0개의 댓글