과제 중에 적었던 내용이지만 마무리하지 않아 오늘 마무리를 해본다.
테이블뷰를 만드는 과정에서 항목을 추가할 때 3개 이상 항목을 추가하게 되면
장바구니에는 담기지만 뭘 추가했는지 굳이 스크롤을 내려가며 봐야하는 불편함이 있었다.
그렇게 스크롤이 사용자가 추가하는 메뉴를 추적하며 따라가게 해주는 기능이 필요했고,
우여곡절 끝에 UITableView
에 기본적으로 있는 scrollToRow
기능을 이용하면 된다는 걸 알게 됐다.
번역하자면 ,
" 인덱스 경로가 식별한 행이 화면의 특정 위치에 있을 때까지 테이블 보기를 스크롤합니다. "
at indexPath: IndexPath
첫번째 줄의 코드의 의미는 어느 행으로 스크롤할지 정해줘야 한다는 의미이다.
IndexPath
는 섹션(section)과 행(row) 정보를 가지고 있는데,
만약 IndexPath(row: 2, section: 0)
이라면 첫 번째 섹션의 세 번째 행을 의미한다.
at scrollPosition: UITableView.ScrollPosition
그리고 두번째 줄의 코드는 스크롤했을때
그 행이 화면에서 어디에 위치해야 하는지를 지정한다는 의미다.
주로 사용하는 값은 아래의 내용을 보면 된다.
animated: Bool
그리고 이 내용은 스크롤이 애니메이션 효과를 사용해 부드럽게 이동할지를 결정한다고 한다.
대부분은 true 로 많이 한다. 부드럽게 넘어가야 자연스러우니까!
if cart.count > 0 {
tableView.layoutIfNeeded()
let lastIndex = IndexPath(row: cart.count - 1, section: 0)
tableView.scrollToRow(at: lastIndex, at: .bottom, animated: true)
}
tableView.reloadData()
}
if cart.count > 0 {
cart
배열에 아이템이 하나 이상 있을 때만 실행한다.
(참고로 메뉴데이터 배열을 cart라는 값에 담았다)
조건문인 if문을 이용해 카트가 비워져 있지 않다면의 조건을 걸었다.
tableView.layoutIfNeeded()
테이블 뷰가 필요하다면 레이아웃을 즉시 업데이트한다라는 뜻인데,
이유는 화면 표시를 최신 상태로 유지하기 위해 필요한 레이아웃 작업을 처리하기 위함이다.
layoutIfNeeded
: 간단히 설명하자면 UIKit에서 뷰의 레이아웃을 즉시 업데이트하기 위해 사용하는 메서드로, 주로 레이아웃이 변경되었을 때 해당되는 변경 사항을 바로 화면에 반영하고 싶을 때 사용된다.
let lastIndex = IndexPath(row: cart.count - 1, section: 0)
마지막 아이템의 인덱스를 계산해서 IndexPath
객체를 생성한다.
풀어 설명하자면 카트의 마지막 행(인덱스)을 찾아 저장한다는 뜻이다.
왜 count - 1이 마지막 아이템의 인덱스일까? (사실 내가 처음에 이해 못해서 씀)
자. 배열의 인덱스는 0부터 시작하지만 count는 아이템의 개수를 나타낸다.
따라서, 마지막 아이템의 인덱스를 구하려면 전체 개수에서 1을 뺀 값이 필요하다는 것인데,
최최최최종으로 비유로 설명하자면 이렇다.
배열의 인덱스를 서랍으로 비유해보는 것이다.
서랍 개수(count) : 서랍의 총 개수 (4개)
서랍 번호(인덱스) : 서랍의 위치 (0번부터 시작)
서랍이 4개 있다면, 서랍 번호는 0번, 1번, 2번, 3번이다.
마지막 서랍의 번호는 총 서랍 개수(4개)에서 1을 뺀 값이다.
→ 마지막 서랍 번호 = 4 - 1 = 3 (짜잔)
tableView.scrollToRow(at: lastIndex, at: .bottom, animated: true)
마지막 행(lastIndex
)으로 스크롤할건데,
at: .bottom
은 해당 행을 화면 아래쪽에 위치하도록 한다는 뜻이고,
animated: true
는 스크롤이 부드럽게 이동하도록 한다는 것이다.
공식 문서의 매개변수 | 나의 코드 | 설명 |
---|---|---|
at indexPath: IndexPath | lastIndex | 마지막 행의 위치를 나타냄. |
at scrollPosition: .bottom | .bottom | 마지막 행이 화면의 맨 아래에 위치함. |
animated: Bool | animated: true | 부드럽게 스크롤 이동함. |
카트에 아이템이 있다면, 테이블 뷰를 업데이트하고 마지막 아이템이 화면 아래쪽에 보이도록 스크롤한다
이제 메뉴를 여러개 담게 되면 맨 마지막에 있는 메뉴를 따라 스크롤이 이동하게 된다.
근데 animated: false로 하면 궁금해서 차이를 보고 싶었는데,,,
아무리 봐도 별 차이가 없었다. 뭐지? 분명 뚝뚝 끊어진다고 했던 것 같은데,
두 값의 차이를 다시 한 번 확인했다.
.
.
.
.
.
.
바로 테이블 뷰의 크기와 마지막 셀의 위치 때문이었는데,
만약 현재 테이블 뷰의 컨텐츠가 화면에 거의 다 보이고 있다면
이동 거리가 짧아 애니메이션 효과가 당연히 두드러지지 않을 것이다.
스크롤이 엄~청 길다면 animated: true
와 animated: false
의 차이가 명확해질 수 있지만,
만약 마지막 셀이 이미 화면에 보이는 상태라면..
스크롤할 필요가 없으므로 애니메이션 효과가 발동되지 않는다는 것을 알았다.
비유해보자면
scrollToRow
는 테이블 뷰의 "위치를 찾는 네비게이션 시스템" 처럼 작동한다고 볼 수 있겠다.
indexPath
는 도착지의 좌표,
scrollPosition
은 최종 위치,
animated
는 이동 방식(부드럽게 or 즉시)을 정한다.
그리고 indexPath
를 계산할 때
count - 1
처럼 배열의 기본 동작 (0부터 시작) 을 항상 염두에 두어야 한다는 점도 확인을 잘 해야겠다 싶었다.
scrollToRow
를 앞으로 있을 프로젝트에서 더 많이 사용해 보며 테스트를 해보고 싶다는 생각을 하기도 하고..
아 특히 공식 문서를 기반으로 매개변수를 해석하고 알아가는 과정이 정말 깊이 있는 학습을 위한 좋은 발걸음이란 걸 알게 되었다.
오늘을 통해 테이블 뷰의 스크롤 제어와 관련된 메서드를 다루는 능력을 한 단계 끌어올리는 계기가 된 것 같아 기분이 좋다.
오,, 저도 적용해보고 싶어요
프로젝트를 전부 1주하고 버리고 2주하고 버리고 이러니까 리팩터링해보는 시간이 없어서 아쉽