How to cleanly hide a UITableView Section
--
Take any app.
Go to Settings.
There’s a pretty good chance you’ll find a UITableView with grouped sections.
Most apps are built with at least one UITableView subclass, and there’s often a need to show / hide a specific section based on user settings or access to features.
We don’t get isHidden out of the box
UITableView, which is a subclass of UIScrollView and has been around since iOS 2.0, doesn’t come with a handy isHidden
property, so the logic has to be handled in the datasource and delegate. This can get spaghetti-like very quickly as the logic spans across the protocol implementation and if
else
statements are scattered throughout the required and optional methods.
Minimize code complexity
It’s tempting to handle each specific case and set numberOfSections
to n when showing the section, and n-1 when hiding the section, but this gets complicated when we have to handle the individual cell logic in cellForRowAt indexPath
and in subsequent setup. There are over 40 datasource and delegate methods to keep track of, and code maintenance can get tricky from here.
There’s a better way.
The solution
Let’s start withnumberOfRowsInSection
and return 0
for Section to Hide. This is a good start, but we’ll still end up with an empty section that takes up space as a result of the header / footer padding.
Adjust for layout
To adjust for the extra spacing, we can override the delegate method heightForHeaderInSection
and return CGFloat.leastNonzeroMagnitude
for our hidden section.* Note that returning 0 here will not work; there must be a value for the height.
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { return shouldHideSection ? CGFloat.leastNonzeroMagnitude : 20}
If you’re already overriding titleForHeaderInSection
, you’ll also need to set the section title to nil
.
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { return shouldHideSection ? nil : "Section Title"}
*You may also need to override heightForFooterInSection
or set the footer value to < 1 in the storyboard.