본문 바로가기
  • Apple Developer Academy @ POSETECH 1기, 비전공자의 일지
  • WWDC 22 Swift Student Challenge Winner
  • 프라하에서 애플 아카데미 면접을 본 썰...
⌨️ UIKit

UIKit UICollectionView 에서 초기값이 선택되어 있게 만들기 - PreSelected

by PecanPieiOS 2023. 5. 1.

UICollectionView 를 쓰면서 초기 값이 선택이 되어 있어야 하는 상황에 맞닥뜨렸다. 

콜렉션뷰나 테이블뷰나 보통 리스트를 만들고, select 할 것을 찾고 나서 누르는 상황이 나오기 때문에

어떤 cell 이 preSelected 라는게 된다는 건 자주 나올 수 없는 상황이다.

하지만 어떤 경우에는 꼭 필요한 경우가 있을 것이다.

 

SOPT iOS 과제를 하던 중, Tving 의 컴포넌트를 구현하면서 진행하고 있었다.

MVVM 로 진행하면서 이번에 처음으로 VC 에 직접 뷰를 그려보지 않겠다 라는 마음으로, 세부 View 를 따로 그리고 있었다.

위에 보이는 Header Tap View 를 UICollectionView 로 구현을 하고 있었는데, 첫 cell 이 기본적으로 선택이 되어 있었다.

 

그래서 UICollectionView 의 delegate 이든 dataSource 든 어떤 메서드가 있겠지 하고서는 평범하게 접근을 했다.

검색을 하고 초기 선택 값을 어떻게 처리해야 하나 찾았다. (초기 선택값이 있는 기능은 처음이었던 것 같기도..?)

https://woongsios.tistory.com/107

 

cellForItemAt: 에서 select 해주기

cell이 select 되었을 때 셀에 어떤 처리를 해주는 경우가 많이 있죠. cellForItemAt: 에서 원하는 cell을 select 해주려면 어떻게 해야할까요? 접근 먼저 select를 처리해주는 방법부터 알아볼까요? delegate를

woongsios.tistory.com

다음 블로그를 참고하며 음 너무 쉬운뎨? 하면서

Cell 을 그리는 메서드인 "cellForItemAt" 에 코드를 집어넣었다.

func collectionView(_ collectionView: UICollectionView,
	cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: 
    HomeHeaderTabCollectionViewCell.cellIdentifier, for: indexPath) as? HomeHeaderTabCollectionViewCell 
    else { return UICollectionViewCell() }
    
    if indexPath.item == 0 { 
    	cell.isSelected = true
        collectionView.selectItem(at: indexPath, 
        animated: false, scrollPosition: .init())
    }
    
    ...
}

 

multipleSelection 을 쓰는 건 조금 말이 안되기 때문에, .selectItem(...) 을 썼다.

indexPath 가 0번째일 때, cell 은 선택이 되어있다. 라는 심플한 구조였다.

그런데 이제 실제로 돌려보면, 내가 내 상황에 맞지 않게 멍청하게 가장 기본이 되는 원리를 무시하고 썼다. Scroll 이 안되는 CollectionView 에서는 아무 문제가 없었지만,

 

ISSUE:

Scroll 이 되고 cell 이 reuse 되면서 다시 불러지면,

내가 마지막 indexPath 의 item 을 선택했다 하더라도 0번째 indexPath 의 cell 이 불려지는 순간 나의 의지와는 상관 없게 첫번째 item 이 강제적으로 select 가 되는 문제가 발생했던 것이죠...

 

[<- 첫 item 이 다시 그려지면 내 강제적으로 선택이 초기화된다. 왜냐면 코드가 그러하니깐... 코드 네버 라이]

 

 

 

 

 

 

 

 

 

 

 

그래서 다른 delegate 이나 dataSource 에서 방법이 있을까 하다가, 

간단하게 1) UICollectionView 내부에서 조건을 걸고, 2) 외부 변수에 Bool 로 조건을 달아서 

처음 그려졌을 때만 선택이 되어 있게 하자. 어차피 다른 item 을 누르고 이동해야지 문제가 생기니깐!

(그냥 첫번째 item 이 선택이 되어 있는 상태로 유지가 되는 상황이면 issue 랄게 없어지잖아?!)

 

순서가 조금 이상하게 적혔는데, 2) 부터 설명하면

private var isHomeSelected = true

UICollectionViewDelegate 함수들 외부에 다음과 같은 Bool 값을 초기값으로 받아 놓는다.

이 의미는 현재 Home 이라는 탭이 선택이 되어 있는가? 라는 그냥 간단한 조건이다.

 

1) 그리고 함수 내부(cellForItemAt: )에는 초기 선택될 그 조건이 추가가 되는 것이다.

if indexPath.item == 0 && isHomeSelected == true {
    cell.isSelected = true
    collectionView.selectItem(at: indexPath, animated: false, scrollPosition: .init())
}

isHomeSelected 도 동시에 true 일 때만 첫번째 cell 이 선택이 되어 있을거다.

즉, 뷰가 처음 그려졌을 때는 무조건 선택이 되어 있을 것이다. 라는 얘기이다.

 

추가적으로, 위에서 말했듯이 다른 item 을 눌러야 Issue 가 발생하는 상황이기 때문에 didSelectItemAt(: ) 함수를 사용해야 했다.

만약, 다른 item 을 누르면 0번째 item 이 다시 그려져도 select 가 되면 안되니깐 말이다.

그래서 우리가 추가한 조건을 false 로 바꾼다. 그러면 위의 조건은 만족하지 않게 된다.

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
    ...
    isHomeSelected = false
    
    ...
}

 

이렇게 바꾸고 나니, 선택이 초기화되는 Issue 는 해결됐다. 끝.

 

사실 별건 아닌데, 뭔가 뚝딱 해결한 것 같아 뚝딱뚝딱 적어 올린다.

TIL 하면서 느낀건 어떻게든 적고 정리하면 이해가 확실히 깊어지는 느낌이라.

SOPT iOS 짱

댓글