Intro
UITableView 를 별 다른 설정없이 인스턴스화해서 사용해보면 Style 기본값이 .plain
으로 설정되어 있어 Header 를 사용하는 경우 스크롤을 하더라도 바로 사라지는 것이 아니라 계속 남아있게 되는데요. 이것을 해결하려면 tableView 의 Style 을 .grouped
로 지정해주면 Header 가 다른 셀들과 같은 방식으로 스크롤되게 됩니다.
그런데 이렇게 사용하면 문제점이 하나 발생하는데 우리는 Footer 가 필요없고 Header 만 필요한 경우에도 자동적으로 Footer 까지 생성되는 상황이 발생하는거에요. 이것 때문에 골치를 여러번 썩으면서도 공부해서 해결하기보다 바쁘다는 핑계로 여태까지 우회하는 방법으로 해결을 했었거든요. 그런데 오늘 프로젝트를 진행하면서 같은 상황을 또 마주치게 되어 확실히 해결하는 방법을 공부해보았습니다.
Preconfigure
간단하게 연습해보기 위해 ViewController 에 Grouped Style 로 UITableView 를 하나 올려놓았어요. 그리고 tableView(_:viewForHeaderInSection:)
를 구현하고 회색 BackgroundColor 를 가진 뷰를 리턴했습니다.
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let view = UIView()
view.backgroundColor = .gray
return view
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 10
}
.plain
Style 에서 이렇게 구현했다면 Header 만 생성되었을텐데요. Apple 이 기본세팅을 왜 이렇게 해놓았는지 모르겠지만 .grouped
Style 에서는 자동적으로 Footer 뷰까지 생성이 됩니다.
우리는 분명히 Header 를 회색으로 지정해 놓았는데 빨간색 화살표로 표시된 부분에 우리는 생성한적 없는 다른 뷰가 하나 있잖아요? 저게 바로 Footer 입니다. 자동으로 생성되었어요. 처음에는 저게 Footer 라는 사실을 몰라서 더 많이 헤맸던 것 같아요. 알고나니 해결법이 정말 간단했습니다.
Solution
그럼 코드를 작성해볼게요.
tableView.tableFooterView = UIView(frame: .zero)
tableView.sectionFooterHeight = 0
직접 UIView 를 생성해 Footer 뷰로 지정해주고 높이를 0 으로 바꿔주었어요. 이유는 알 수 없지만 기본적으로 제공되는 Footer 의 높이를 0 으로 바꾸는 방법은 통하지 않더라고요. 이제 이렇게 세팅하고 Simulator 를 실행해 볼게요.
오!! 사라졌어요. 처음부터 기본값이 이렇게 세팅되어 있었다면 더 편했겠지만 굳이 그렇게하지 않은 이유가 분명 Apple 에게는 있을거에요. 그럴거에요.
Entire Code
import UIKit
class ViewController: UIViewController {
// MARK: - Properties
let tableView = UITableView(frame: .zero, style: .grouped)
// MARK: - Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
configureUI()
}
// MARK: - UI
private func configureUI() {
setAttributes()
setContraints()
}
private func setAttributes() {
tableView.dataSource = self
tableView.delegate = self
tableView.tableFooterView = UIView(frame: .zero)
tableView.sectionFooterHeight = 0
}
private func setContraints() {
view.addSubview(tableView)
tableView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
tableView.topAnchor.constraint(equalTo: view.topAnchor),
tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
])
}
}
extension ViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
return UITableViewCell()
}
}
extension ViewController: UITableViewDelegate {
func numberOfSections(in tableView: UITableView) -> Int {
return 10
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let view = UIView()
view.backgroundColor = .gray
return view
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 10
}
}