UITableView
content inset
iOS development
Swift programming
UITableView customization

Set UITableView content inset permanently

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

UITableView content inset settings can appear to reset due to safe area adjustments, navigation bar behavior, and automatic scroll view policies. If you need a permanent custom inset, you must control both inset assignment and adjustment behavior. A stable solution applies inset consistently across lifecycle events.

Why Insets Change Unexpectedly

UITableView is a scroll view, so iOS may adjust insets automatically when embedded in navigation controllers or when safe areas change. This can override manual values after rotation, view appearance transitions, or status bar changes.

To keep inset permanent, disable unwanted automatic adjustments and reapply predictable values.

Basic Permanent Inset Setup

Set contentInset and matching scrollIndicatorInsets together.

swift
1import UIKit
2
3final class FeedVC: UITableViewController {
4    override func viewDidLoad() {
5        super.viewDidLoad()
6
7        tableView.contentInset = UIEdgeInsets(top: 16, left: 0, bottom: 24, right: 0)
8        tableView.scrollIndicatorInsets = tableView.contentInset
9    }
10}

Keeping indicators aligned improves visual consistency.

Disable Automatic Adjustment Behavior

For iOS 11 and later, set adjustment behavior to never if system modifications conflict with your intent.

swift
1override func viewDidLoad() {
2    super.viewDidLoad()
3    tableView.contentInsetAdjustmentBehavior = .never
4}

Then manually account for safe area if needed.

Reapply Insets in Layout Lifecycle

Insets may still need recalculation after layout changes. Use viewDidLayoutSubviews for stable final geometry.

swift
1override func viewDidLayoutSubviews() {
2    super.viewDidLayoutSubviews()
3
4    let top = view.safeAreaInsets.top + 8
5    let bottom = view.safeAreaInsets.bottom + 16
6    let inset = UIEdgeInsets(top: top, left: 0, bottom: bottom, right: 0)
7
8    if tableView.contentInset != inset {
9        tableView.contentInset = inset
10        tableView.scrollIndicatorInsets = inset
11    }
12}

Conditional assignment avoids unnecessary layout churn.

If table starts beneath a custom header or translucent bar, set initial content offset carefully after inset assignment.

swift
1override func viewDidAppear(_ animated: Bool) {
2    super.viewDidAppear(animated)
3    if tableView.contentOffset.y == 0 {
4        tableView.setContentOffset(CGPoint(x: 0, y: -tableView.adjustedContentInset.top), animated: false)
5    }
6}

This prevents first-load jump behavior.

Permanent Inset Utility Pattern

Create one helper to apply insets consistently across screens.

swift
1func applyPermanentInset(_ tableView: UITableView, top: CGFloat, bottom: CGFloat) {
2    let inset = UIEdgeInsets(top: top, left: 0, bottom: bottom, right: 0)
3    tableView.contentInset = inset
4    tableView.scrollIndicatorInsets = inset
5}

Centralization reduces duplicate logic and inconsistent UI behavior.

Some layouts need fixed breathing room above first cell and below last cell regardless of dynamic content changes. You can combine insets with explicit header and footer views for stable visual spacing.

swift
1let topSpacer = UIView(frame: CGRect(x: 0, y: 0, width: 1, height: 12))
2let bottomSpacer = UIView(frame: CGRect(x: 0, y: 0, width: 1, height: 20))
3
4tableView.tableHeaderView = topSpacer
5tableView.tableFooterView = bottomSpacer

This approach complements content inset and reduces dependence on repeated offset adjustments.

Handle Keyboard Insets with Permanent Base Insets

When keyboard appears, additive inset logic works best. Keep a stored base inset and apply keyboard delta on top of it.

swift
1var baseInset = UIEdgeInsets(top: 16, left: 0, bottom: 24, right: 0)
2
3func applyKeyboardHeight(_ h: CGFloat) {
4    var inset = baseInset
5    inset.bottom += h
6    tableView.contentInset = inset
7    tableView.scrollIndicatorInsets = inset
8}

This prevents cumulative inset drift over repeated keyboard events.

Rotation and Size Class Changes

Insets may need recomputation when device rotates or split-view size changes. Trigger reapplication in size transition callbacks for predictable behavior.

swift
1override func viewSafeAreaInsetsDidChange() {
2    super.viewSafeAreaInsetsDidChange()
3    viewDidLayoutSubviews()
4}

Consistent reapplication logic keeps spacing stable across orientation changes.

Testing Permanent Inset Behavior

Verify behavior under navigation pushes, modal presentation, keyboard appearance, and rotation. Permanent inset logic often appears correct in one path but fails in another. A short QA checklist helps catch these issues early.

Common Pitfalls

  • Setting contentInset once and ignoring automatic system adjustments.
  • Forgetting to update scrollIndicatorInsets.
  • Reapplying insets every frame without change checks.
  • Mixing safe-area logic across multiple lifecycle methods inconsistently.

Summary

  • Permanent table insets require control of both manual values and auto-adjustment behavior.
  • Use contentInsetAdjustmentBehavior and lifecycle reapplication when needed.
  • Keep indicator insets aligned with content inset.
  • Centralize inset logic for consistent screens.

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.