UITableView의 헤더 고정 여부를 알아내는 방법

Jongwon Woo
3 min readDec 5, 2020

--

헤더가 고정되면 파랑이 됩니다.

디자인 요구사항 중에는 리스트의 헤더가 상단에 고정될 때 디자인이 달라지기를 원하는 경우가 있습니다. 위의 이미지처럼 오렌지색 헤더가 파랑이 되는 것처럼 말이죠.

저런 리스트를 UITableView로 만들면 헤더 고정은 쉽습니다. 그런데 UITableView는 헤더가 고정 상태로 바뀌는 것을 알려주진 않습니다. 알려주면 참 편할텐데…알려주지 않으니 알아내야 합니다.

헤더가 고정되는 원리는 테이블뷰의 contentOffset이 변할 때 고정된 헤더의 frame이 고정된 위치를 유지하도록 같이 변합니다. 그렇다면 반대로 테이블뷰가 헤더의 고정을 풀려면 테이블뷰는 헤더의 원래 frame를 알고 있어야 합니다.

이건 헤더의 원래 frame과 현재 frame이 다르다면 헤더는 고정된 상태라는 의미입니다.

이걸 구현하면 원하는 걸 얻을 수 있습니다.

let headerOriginalFrame = self.myTableView.rectForHeader(inSection: header.tag)
let headerCurrentFrame = header.frame
let fixed = headerOriginalFrame != headerCurrentFrame

전체 소스 코드는 여기에 있습니다. https://github.com/jongwonwoo/CodeSamples/blob/master/TableView/TableviewFixedHeader/Tableview/ViewController.swift

P.S. 결과물을 보면 허무할 정도로 쉽고 간단한 경우가 있습니다. 그런데 그 과정은 그렇지 않은 경우가 많습니다. 그래서 그 과정을 사족처럼 적어둡니다.

첫 번째 시도. 이 시도는 저의 동료가 했던 시도입니다. 헤더가 만들어질 때 원래 frame을 저장해두고 contentOffset이 변할 때마다 현재 frame과 비교해봅니다. 대부분의 경우에 잘 동작하지만 문제가 있습니다. 셀이 추가되거나 삭제되면 저장해둔 원래 frame이 쓸모없어지는 경우가 발생합니다. 기준이 변하니까 비교를 할 수 없습니다.

두 번째 시도. 이 시도는 첫 번째 시도를 보고 제가 했던 시도입니다. 원래 frame이 변하는 것을 보고 이것에 의존하지 않는 방법을 찾으려고 했습니다. 그래서 헤더의 현재 frame의 y 값이 테이블뷰의 y와 같다면 고정된 상태일 것이다라는 가정을 실험했습니다. 그런데 테이블뷰를 드래깅할 때는 잘 동작하는 것 같지만 빠르게 스크롤하면 문제가 생겼습니다. 빠르게 스크롤되는 동안 고정된 헤더의 현재 frame이 널뛰듯이 달라집니다. 이것도 기준이 변하기 때문에 쓸모가 없습니다.

세 번째 시도. 흔들리지 않는 기준은 무엇일까를 고민했던 시도였고 그 결과가 위에 있는 소스 코드입니다. 애플 문서를 살피고, 테이블뷰의 헤더와 셀의 레이아웃이 정해지는 시점을 확인하고, 셀을 추가/삭제도 해보고, 스크롤을 천천히/빠르게 해보면서 값을 확인했습니다.

--

--