UIScrollView
horizontal paging
Mobile Safari
iOS development
Swift programming

UIScrollView horizontal paging like Mobile Safari tabs

Interview Questions practice on Codemia

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

Browse interview questions

Introduction

Building horizontal paging with UIScrollView can recreate the smooth tab-like behavior users know from Mobile Safari. The core mechanics are simple: paging-enabled scroll view, child views laid out side by side, and synchronized tab state. The hard part is performance and lifecycle management when there are many pages or dynamic content.

This article provides a practical Swift approach with code, plus guidance on when to switch to UIPageViewController or a collection-view based architecture.

Core Sections

1) Configure the scroll view for paging

swift
1let scrollView = UIScrollView()
2scrollView.translatesAutoresizingMaskIntoConstraints = false
3scrollView.isPagingEnabled = true
4scrollView.showsHorizontalScrollIndicator = false
5scrollView.alwaysBounceVertical = false
6scrollView.delegate = self

Constrain it to container bounds and ensure each page width equals viewport width for snap paging.

2) Lay out page content horizontally

swift
1let pages: [UIView] = [page1, page2, page3]
2for (index, page) in pages.enumerated() {
3    page.frame = CGRect(
4        x: CGFloat(index) * view.bounds.width,
5        y: 0,
6        width: view.bounds.width,
7        height: view.bounds.height
8    )
9    scrollView.addSubview(page)
10}
11scrollView.contentSize = CGSize(
12    width: CGFloat(pages.count) * view.bounds.width,
13    height: view.bounds.height
14)

If using Auto Layout, use a horizontal stack container inside the scroll view with equal-width constraints.

3) Sync selected tab with page index

swift
1func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
2    let page = Int(round(scrollView.contentOffset.x / scrollView.bounds.width))
3    tabControl.selectedSegmentIndex = page
4}
5
6@IBAction func tabChanged(_ sender: UISegmentedControl) {
7    let x = CGFloat(sender.selectedSegmentIndex) * scrollView.bounds.width
8    scrollView.setContentOffset(CGPoint(x: x, y: 0), animated: true)
9}

This keeps gesture and tap navigation consistent.

4) Optimize memory for many pages

For large page counts, preloading every page view is expensive. Use child view controller containment and lazy loading for nearby pages only. Recycle off-screen pages when content can be rebuilt quickly.

If page content is homogeneous, UICollectionView with paging often provides better reuse primitives than raw UIScrollView.

5) Handle rotation and safe areas

On size changes, recompute page frames and preserve current index.

swift
1override func viewDidLayoutSubviews() {
2    super.viewDidLayoutSubviews()
3    let current = Int(round(scrollView.contentOffset.x / max(scrollView.bounds.width, 1)))
4    layoutPages()
5    scrollView.contentOffset.x = CGFloat(current) * scrollView.bounds.width
6}

Without this, orientation changes can shift users to partial pages.

6) UX polish checklist

Add a lightweight indicator animation and haptic feedback on tab jumps for a more native feel. Keep gesture conflict rules clear if nested horizontal scroll views exist. For accessibility, expose page titles and announce page changes with VoiceOver notifications.

Performance-test on low-memory devices where image-heavy pages can trigger stutters if preloaded aggressively.

7) Production checklist for UIScrollView paging UX

Treat this topic as an operational concern, not only a coding snippet. Start by defining one explicit success metric that reflects business behavior, such as failed request rate, pipeline lag, model quality drift, or user-visible latency. Then create a small acceptance checklist that can run in both staging and production-like test environments. The checklist should verify the happy path, at least one failure path, and one boundary case.

Capture configuration assumptions close to the implementation, including timeouts, versions, environment variables, and external dependencies. If behavior varies by environment, encode those differences in configuration rather than hardcoded branches. Add lightweight observability from day one: key counters, error categorization, and structured logs with identifiers that support correlation during incident response.

Finally, define rollback and ownership before rollout. Decide who responds to alerts, what threshold should trigger rollback, and which fallback mode keeps the system functional if this component degrades. A clear ownership and rollback plan turns isolated technical knowledge into a maintainable production practice.

Common Pitfalls

  • Setting isPagingEnabled but giving pages widths that do not match viewport width.
  • Preloading too many complex page views and causing memory spikes.
  • Forgetting to sync tab control when users swipe manually.
  • Not recalculating layout after rotation or split-view size changes.
  • Ignoring gesture conflicts with nested scroll views.

Summary

UIScrollView horizontal paging can deliver a Safari-like tab experience when layout, state sync, and lifecycle are handled carefully. For a few pages, direct paging is simple and effective. For larger or dynamic page sets, move toward reusable architectures. Whichever approach you choose, prioritize consistent page geometry and performance under real device constraints.


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.