문제 상황
컬렉션 뷰에서 가로 스크롤하면 컬렉션 뷰가 최상단으로 강제 이동하는 문제가 발생했다.
이 문제는 adjustContentInset() 메서드의 호출 타이밍과 UICollectionView의 동작 방식이 충돌하면서 발생한 것으로 분석되었다.
adjustContentInset()의 역할
원인 분석
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
DispatchQueue.main.async {
self.adjustContentInset()
}
}
Swift
복사
viewDidLayoutSubviews()에서 호출했을 때의 문제
•
컬렉션 뷰가 새로운 아이템을 로드하거나 레이아웃이 조정될 때마다 adjustContentInset()이 반복 실행됨
•
scrollToItem(at:animated:scrollPosition:)이 불필요하게 호출되면서 가로 스크롤 시에도 컬렉션 뷰가 최상단으로 강제 이동하는 문제 발생
이전 코드에서는 viewDidLayoutSubviews()에서 adjustContentInset()을 호출했다.
하지만 viewDidLayoutSubviews()는 뷰의 레이아웃이 변경될 때마다 반복적으로 호출되므로 불필요한 스크롤 이동이 발생하는 문제가 있었다.
해결 방법
viewWillAppear(_:)에서 adjustContentInset() 메서드를 호출하니 해결되었다.
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
DispatchQueue.main.async {
self.adjustContentInset()
}
}
Swift
복사
viewWillAppear(_:)를 사용한 이유
•
뷰가 나타나기 직전에 단 한 번 실행되므로 불필요한 반복 실행을 방지할 수 있음
•
레이아웃이 완전히 설정된 후 실행되므로 viewDidLayoutSubviews()에서 실행할 때처럼 불필요한 호출이 발생하지 않음
•
최초 설정 시에만 scrollToItem(at:animated:scrollPosition:)이 실행되므로 가로 스크롤 시 최상단으로 이동하는 문제가 해결됨
결론
viewDidLayoutSubviews() | viewWillAppear(_:) | |
호출 횟수 | 여러 번 (뷰의 크기나 레이아웃 변경 시마다 실행됨) | 한 번 (뷰가 화면에 나타날 때 실행됨) |
스크롤 이동 버그 | scrollToItem이 반복 실행되어 가로 스크롤 시 최상단으로 이동 | 불필요한 스크롤 이동 없음 |
최적 사용 시점 | 보통 동적인 크기 조정이 필요한 경우 사용 | 한 번만 실행해야 하는 초기 설정 로직에 적합 |
adjustContentInset()은 초기 설정 시 한 번만 실행되면 되므로
viewDidLayoutSubviews()가 아닌 viewWillAppear(_:)에서 실행해야 한다!
요약
•
viewDidLayoutSubviews()에서 adjustContentInset()을 호출하면 뷰의 레이아웃이 변경될 때마다 반복 실행됨
•
가로 스크롤 시 scrollToItem이 반복 호출되면서 최상단으로 이동하는 버그 발생
•
viewWillAppear(_:)에서 adjustContentInset()을 호출하도록 변경
•
뷰가 나타나기 직전에 한 번만 실행되므로 불필요한 스크롤 이동이 발생하지 않음