Creating Scrollable Interfaces Using UIScrollView
Course: iOS App Development Training
Topic: Creating Scrollable Interfaces Using UIScrollView
Course Link: iOS App Development Training Course
Demo Link: Register for a Course Demo
Official Website: JustAcademy
1. Introduction to UIScrollView
In iOS application development, interfaces often contain more content than can fit on a single screen. Examples include registration forms, profile pages, product details, articles, settings screens, and image galleries. A scrollable interface allows users to move through this content without reducing its readability or removing important information.
UIScrollView is a UIKit class that provides scrolling and zooming capabilities for content displayed inside a defined visible area. It allows users to move vertically or horizontally through content by swiping or dragging. The scroll view displays only the portion of the content that fits within its frame while allowing the user to access the remaining content through scrolling.
According to Apple’s documentation, a scroll view manages scrolling through properties such as contentSize and contentOffset, and supports Auto Layout through contentLayoutGuide and frameLayoutGuide.
Why Is UIScrollView Important?
- It makes long forms usable on smaller devices.
- It allows users to read lengthy text without shrinking the font size.
- It supports horizontally scrolling content such as image galleries and card collections.
- It can support zooming for suitable content, such as images and diagrams.
- It helps interfaces adapt to different device sizes and orientations.
- It works with Auto Layout to create responsive interfaces.
2. Learning Objectives
After completing this topic, learners should be able to:
- Explain the purpose and working of
UIScrollView.
- Differentiate between the scroll view's visible frame and its content area.
- Create vertical and horizontal scrollable interfaces using Swift.
- Configure content size, scrolling direction, and scroll indicators.
- Build scrollable layouts using Auto Layout constraints.
- Understand the role of content and frame layout guides.
- Respond to scrolling events through
UIScrollViewDelegate.
- Identify common scrolling problems and troubleshoot them.
3. Understanding the UIScrollView Architecture
A scroll view is a container view. It displays its child views within a viewport and adjusts the visible portion of the content as the user scrolls.
Important Components
| Component |
Description |
Example |
| UIScrollView |
The container that handles scrolling gestures and displays a portion of the content. |
A scrollable profile screen. |
| Content View |
A regular UIView placed inside the scroll view to hold and organize interface elements. |
A vertical stack of labels, images, and buttons. |
| Viewport or Frame |
The visible rectangular area through which the user sees the content. |
The portion of a long form currently visible. |
| Content Size |
The total size of the scrollable content area. |
A content height of 1,500 points inside a 700-point viewport. |
| Content Offset |
The position of the visible viewport relative to the content. |
Moving down a long article changes the vertical offset. |
| Scroll Indicators |
Visual indicators that show the user's approximate position in the content. |
A vertical indicator beside a long page. |
How Scrolling Works
- The application creates a
UIScrollView and adds it to the view hierarchy.
- Scrollable content is placed inside the scroll view.
- The content area is defined using Auto Layout constraints or an explicit
contentSize.
- The user swipes or drags the content.
- The scroll view updates its visible position by adjusting its content offset.
- The user can access content that was initially outside the visible frame.
4. Important UIScrollView Properties
| Property |
Purpose |
Example |
contentSize |
Defines the total content width and height when using explicit sizing. |
CGSize(width: 350, height: 1200) |
contentOffset |
Represents the current visible position within the content. |
scrollView.contentOffset.y |
isScrollEnabled |
Enables or disables scrolling. |
scrollView.isScrollEnabled = true |
showsVerticalScrollIndicator |
Controls the vertical scroll indicator. |
scrollView.showsVerticalScrollIndicator = true |
showsHorizontalScrollIndicator |
Controls the horizontal scroll indicator. |
scrollView.showsHorizontalScrollIndicator = false |
isPagingEnabled |
Makes scrolling settle at page-sized intervals along the scrolling axis. |
Useful for full-screen image pages. |
bounces |
Controls bounce behavior at content boundaries. |
scrollView.bounces = true |
alwaysBounceVertical |
Allows vertical bouncing even when the content is not taller than the frame. |
scrollView.alwaysBounceVertical = true |
contentInset |
Adds custom inset space around the content. |
UIEdgeInsets(top: 16, left: 0, bottom: 16, right: 0) |
contentLayoutGuide |
Provides layout anchors for the scrollable content area. |
Pinning a content view to the scroll view's content edges. |
frameLayoutGuide |
Provides layout anchors for the visible frame of the scroll view. |
Matching the content view's width to the viewport. |
5. Creating a Basic Vertical Scroll View Using Swift
The following example creates a vertical scroll view programmatically. It uses an explicit content size to demonstrate the fundamental scrolling mechanism.
Step 1: Create the Scroll View
import UIKit
class ScrollViewController: UIViewController {
private let scrollView = UIScrollView()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemBackground
configureScrollView()
addContent()
}
private func configureScrollView() {
scrollView.frame = view.bounds
scrollView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
scrollView.backgroundColor = .systemBackground
scrollView.isScrollEnabled = true
scrollView.showsVerticalScrollIndicator = true
scrollView.showsHorizontalScrollIndicator = false
view.addSubview(scrollView)
}
private func addContent() {
let contentHeight: CGFloat = 1400
scrollView.contentSize = CGSize(
width: view.bounds.width,
height: contentHeight
)
let heading = UILabel()
heading.text = "Welcome to iOS Development"
heading.font = .boldSystemFont(ofSize: 26)
heading.frame = CGRect(
x: 20,
y: 30,
width: view.bounds.width - 40,
height: 40
)
scrollView.addSubview(heading)
for index in 1...15 {
let label = UILabel()
label.text = "Learning Section \(index)"
label.font = .systemFont(ofSize: 18)
label.frame = CGRect(
x: 20,
y: CGFloat(index) * 80 + 40,
width: view.bounds.width - 40,
height: 35
)
scrollView.addSubview(label)
}
}
}
Code Explanation
import UIKit imports UIKit classes required for building the interface.
UIScrollView() creates the scroll view instance.
frame = view.bounds initially makes the scroll view occupy the controller's view bounds.
autoresizingMask allows the scroll view's frame to adjust when the parent view changes size.
contentSize sets the total scrollable content area.
addSubview(_:) places labels inside the scroll view.
Important: This example uses frames and a fixed content height to explain the basic concept. For production interfaces, Auto Layout is generally more adaptable across device sizes, text changes, and localization.
6. Creating a Scroll View with Auto Layout
Auto Layout is a constraint-based layout system that determines view positions and dimensions. When a scroll view uses Auto Layout, its visible frame and scrollable content must be described correctly.
A common pattern is to add a content view inside the scroll view. Pin the content view's edges to the scroll view's contentLayoutGuide and match its width to the scroll view's frameLayoutGuide for a vertical-only scrolling layout. The content inside the content view must form an unbroken constraint chain from its top to its bottom so Auto Layout can determine the content height.
Example: Vertical Scroll View with UIStackView
import UIKit
class AutoLayoutScrollViewController: UIViewController {
private let scrollView = UIScrollView()
private let contentView = UIView()
private let stackView = UIStackView()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemBackground
setupScrollView()
setupStackView()
addSections()
}
private func setupScrollView() {
scrollView.translatesAutoresizingMaskIntoConstraints = false
contentView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(scrollView)
scrollView.addSubview(contentView)
NSLayoutConstraint.activate([
scrollView.topAnchor.constraint(
equalTo: view.safeAreaLayoutGuide.topAnchor
),
scrollView.leadingAnchor.constraint(
equalTo: view.leadingAnchor
),
scrollView.trailingAnchor.constraint(
equalTo: view.trailingAnchor
),
scrollView.bottomAnchor.constraint(
equalTo: view.bottomAnchor
),
contentView.topAnchor.constraint(
equalTo: scrollView.contentLayoutGuide.topAnchor
),
contentView.leadingAnchor.constraint(
equalTo: scrollView.contentLayoutGuide.leadingAnchor
),
contentView.trailingAnchor.constraint(
equalTo: scrollView.contentLayoutGuide.trailingAnchor
),
contentView.bottomAnchor.constraint(
equalTo: scrollView.contentLayoutGuide.bottomAnchor
),
contentView.widthAnchor.constraint(
equalTo: scrollView.frameLayoutGuide.widthAnchor
)
])
}
private func setupStackView() {
stackView.axis = .vertical
stackView.spacing = 20
stackView.alignment = .fill
stackView.distribution = .fill
stackView.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(stackView)
NSLayoutConstraint.activate([
stackView.topAnchor.constraint(
equalTo: contentView.topAnchor,
constant: 24
),
stackView.leadingAnchor.constraint(
equalTo: contentView.leadingAnchor,
constant: 20
),
stackView.trailingAnchor.constraint(
equalTo: contentView.trailingAnchor,
constant: -20
),
stackView.bottomAnchor.constraint(
equalTo: contentView.bottomAnchor,
constant: -24
)
])
}
private func addSections() {
for index in 1...12 {
let label = UILabel()
label.text = "Content Section \(index)"
label.font = .systemFont(ofSize: 20)
label.numberOfLines = 0
label.backgroundColor = .secondarySystemBackground
label.layer.cornerRadius = 8
label.clipsToBounds = true
label.textAlignment = .center
stackView.addArrangedSubview(label)
label.heightAnchor.constraint(
greaterThanOrEqualToConstant: 70
).isActive = true
}
}
}
Understanding the Constraints
| Constraint |
Reason |
| Scroll view top, leading, trailing, and bottom |
Defines the visible frame within the controller's view. |
| Content view edges connected to contentLayoutGuide |
Defines the boundaries of the scrollable content. |
| Content view width equals frameLayoutGuide width |
Keeps the content the same width as the visible viewport, creating vertical scrolling. |
| Stack view pinned to content view's top and bottom |
Allows the stack's total height to determine the content height. |
| Arranged subviews have meaningful heights or intrinsic sizes |
Allows Auto Layout to calculate the full content height. |
Key concept: For vertical scrolling, the content height must be able to grow beyond the scroll view's visible height, while the content width is usually constrained to the visible frame. For horizontal scrolling, the content width must be able to grow beyond the frame width.
7. Creating a Horizontal Scroll View
Horizontal scrolling is useful for image carousels, product cards, category selectors, onboarding pages, and horizontally arranged collections.
For a horizontally scrolling Auto Layout layout, constrain the content view's top and bottom edges to the content layout guide, match its height to the frame layout guide, and allow its width to be determined by the horizontal content. Each card should have a defined or intrinsic width.
Example: Horizontal Card Gallery
import UIKit
class HorizontalScrollViewController: UIViewController {
private let scrollView = UIScrollView()
private let stackView = UIStackView()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemBackground
setupGallery()
}
private func setupGallery() {
scrollView.translatesAutoresizingMaskIntoConstraints = false
stackView.translatesAutoresizingMaskIntoConstraints = false
scrollView.showsHorizontalScrollIndicator = true
scrollView.showsVerticalScrollIndicator = false
stackView.axis = .horizontal
stackView.spacing = 16
stackView.alignment = .fill
view.addSubview(scrollView)
scrollView.addSubview(stackView)
NSLayoutConstraint.activate([
scrollView.topAnchor.constraint(
equalTo: view.safeAreaLayoutGuide.topAnchor,
constant: 30
),
scrollView.leadingAnchor.constraint(
equalTo: view.leadingAnchor
),
scrollView.trailingAnchor.constraint(
equalTo: view.trailingAnchor
),
scrollView.heightAnchor.constraint(equalToConstant: 180),
stackView.topAnchor.constraint(
equalTo: scrollView.contentLayoutGuide.topAnchor
),
stackView.bottomAnchor.constraint(
equalTo: scrollView.contentLayoutGuide.bottomAnchor
),
stackView.leadingAnchor.constraint(
equalTo: scrollView.contentLayoutGuide.leadingAnchor,
constant: 16
),
stackView.trailingAnchor.constraint(
equalTo: scrollView.contentLayoutGuide.trailingAnchor,
constant: -16
),
stackView.heightAnchor.constraint(
equalTo: scrollView.frameLayoutGuide.heightAnchor
)
])
for index in 1...6 {
let card = UILabel()
card.text = "Card \(index)"
card.textAlignment = .center
card.font = .boldSystemFont(ofSize: 20)
card.backgroundColor = .systemTeal.withAlphaComponent(0.2)
card.layer.cornerRadius = 12
card.clipsToBounds = true
card.widthAnchor.constraint(equalToConstant: 220).isActive = true
stackView.addArrangedSubview(card)
}
}
}
How the Horizontal Layout Works
- The scroll view has a fixed visible height.
- The stack view arranges cards along the horizontal axis.
- Each card has a width of 220 points.
- The stack view's height matches the scroll view's visible height.
- The stack view's content width grows as more cards are added.
- The user can swipe horizontally to view the remaining cards.
8. Vertical Scrolling vs. Horizontal Scrolling
| Feature |
Vertical Scrolling |
Horizontal Scrolling |
| Direction |
Up and down |
Left and right |
| Typical use cases |
Articles, forms, settings, profile pages |
Carousels, galleries, card rows |
| Content dimension |
Content height exceeds frame height |
Content width exceeds frame width |
| Typical Auto Layout rule |
Content width matches frame width |
Content height matches frame height |
| Stack view axis |
.vertical |
.horizontal |
9. Managing Content Size and Content Offset
Content Size
The contentSize property describes the total scrollable area when content size is set explicitly. It is especially useful in frame-based layouts or when the content dimensions are known. In a well-constrained Auto Layout layout, the scroll view can derive its content size from the constraints instead.
scrollView.contentSize = CGSize(
width: 350,
height: 1500
)
In this example, the content is taller than a typical phone viewport, so vertical scrolling can reveal the additional content. The width and height must match the actual content layout; setting an arbitrary height does not automatically resize or reposition the child views.
Content Offset
The contentOffset property represents the content's current visible position. Changing the offset programmatically can move the scroll view to a specific location.
// Scroll to the top-left content position.
scrollView.setContentOffset(
CGPoint(x: 0, y: 0),
animated: true
)
// Scroll down to a vertical offset of 300 points.
scrollView.setContentOffset(
CGPoint(x: 0, y: 300),
animated: true
)
Use programmatic offsets thoughtfully. A requested offset can be limited by the available content size and adjusted insets.
10. Configuring Scroll Indicators and Bounce Behavior
Scroll indicators give users a visual clue about their current position. Bounce behavior provides feedback when users reach the end of a scrollable area.
scrollView.showsVerticalScrollIndicator = true
scrollView.showsHorizontalScrollIndicator = false
scrollView.bounces = true
scrollView.alwaysBounceVertical = true
Choose these settings according to the interface. For example, a vertical article usually benefits from a vertical indicator, while a horizontal product carousel may hide the vertical indicator and show the horizontal one.
11. Using UIScrollViewDelegate
UIScrollViewDelegate provides methods that allow a view controller or another object to respond to scrolling activity. These methods can be used to update a title, track the current position, adjust interface elements, or perform actions when scrolling ends.
Common Delegate Methods
| Method |
Purpose |
scrollViewDidScroll(_:) |
Called when the visible scroll position changes. |
scrollViewWillBeginDragging(_:) |
Called when the user begins dragging the scroll view. |
scrollViewDidEndDragging(_:willDecelerate:) |
Called when dragging ends, with information about whether deceleration follows. |
scrollViewDidEndDecelerating(_:) |
Called when scrolling deceleration ends. |
scrollViewDidEndScrollingAnimation(_:) |
Called when an animated scrolling movement finishes. |
Example: Detecting Scroll Position
import UIKit
class ScrollDelegateViewController: UIViewController,
UIScrollViewDelegate {
private let scrollView = UIScrollView()
private let statusLabel = UILabel()
override func viewDidLoad() {
super.viewDidLoad()
scrollView.delegate = self
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let verticalPosition = scrollView.contentOffset.y
statusLabel.text = "Vertical offset: \(Int(verticalPosition))"
}
func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
print("User started scrolling")
}
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
print("Scrolling has stopped")
}
}
In a complete application, the scroll view and status label must also be added to the view hierarchy and constrained appropriately. Assigning scrollView.delegate = self enables delegate callbacks for the controller.
12. Supporting Device Rotation and Different Screen Sizes
iOS devices have different screen dimensions, and users may rotate a device or change text sizes. A robust scrollable interface should adapt to these changes without cutting off content or creating unintended scrolling directions.
- Use Auto Layout to define the scroll view's visible frame.
- Use
contentLayoutGuide for the scrollable content boundaries.
- Use
frameLayoutGuide when a content dimension should match the visible frame.
- Prefer stack views for groups of content that need to grow or shrink.
- Allow labels to wrap onto multiple lines where appropriate.
- Avoid hard-coded content heights when text or content can change substantially.
- Test portrait and landscape orientations on different simulator sizes.
13. Keyboard Handling in Scrollable Forms
Forms often contain text fields near the bottom of a screen. When the keyboard appears, it may cover the active field or the submit button. A scroll view can allow the user to move the form so that the active control remains accessible.
UIKit provides the keyboardDismissMode property to configure how dragging interacts with keyboard dismissal.
scrollView.keyboardDismissMode = .interactive
With interactive dismissal, dragging the scroll view can move the keyboard away interactively. This setting alone does not guarantee that the active field is visible. For reliable forms, also consider keyboard layout guides or keyboard notifications, appropriate bottom constraints, and scrolling the active field into view when needed.
14. UIScrollView vs. UITableView vs. UICollectionView
| Component |
Best Use |
Important Difference |
UIScrollView |
Custom content layouts, long forms, mixed interface elements, and simple galleries. |
Provides a scrollable viewport; you manage the content layout. |
UITableView |
Long, primarily row-based lists such as settings, messages, and contacts. |
Provides reusable table cells and list-oriented behavior. |
UICollectionView |
Grids, flexible lists, image galleries, and complex item arrangements. |
Provides reusable cells and configurable layouts. |
Use a plain UIScrollView when the content is a relatively small custom composition of views. For large or frequently updated collections, a table or collection view is usually more suitable because it can reuse cells and manage large data sets efficiently.
15. Common UIScrollView Errors and Troubleshooting
| Problem |
Possible Cause |
Solution |
| Scrolling does not work. |
The content does not exceed the visible frame, scrolling is disabled, or the content size is incorrectly configured. |
Check isScrollEnabled, content dimensions, and the Auto Layout constraints. |
| Content appears cut off. |
The content view's bottom or trailing edge is not constrained, or its size is insufficient. |
Complete the constraint chain and verify content dimensions. |
| Unexpected horizontal scrolling. |
The content width exceeds the frame width or horizontal constraints are incomplete. |
For vertical-only scrolling, match the content view's width to the frame layout guide. |
| Unexpected vertical scrolling. |
The content height exceeds the frame height unintentionally. |
Inspect stack view spacing, child heights, and bottom constraints. |
| Auto Layout warnings appear. |
Conflicting constraints or an incomplete content size definition. |
Review conflicting constraints and ensure the content has a complete top-to-bottom and leading-to-trailing layout. |
| Controls respond instead of scrolling. |
Touch handling, gesture conflicts, or nested scrolling behavior may be involved. |
Review gesture recognizers and the scroll view's touch-handling configuration. |
| The keyboard hides a text field. |
The visible scroll area or keyboard interaction has not been handled. |
Adjust layout for the keyboard and scroll the active field into view when necessary. |
| Content layout breaks after rotation. |
Hard-coded dimensions or incomplete constraints are used. |
Prefer Auto Layout and test multiple device sizes and orientations. |
16. Best Practices for Scrollable Interfaces
- Use Auto Layout for interfaces that must adapt to different devices and text sizes.
- Choose one primary scrolling direction unless two-dimensional scrolling is required.
- Do not mix explicit content sizing and Auto Layout without a clear sizing strategy.
- Make sure the content layout has enough constraints for its size to be determined.
- Use
UIStackView to organize simple vertical or horizontal groups of controls.
- For large data collections, prefer
UITableView or UICollectionView rather than creating hundreds of independent views in a scroll view.
- Test scrolling with interactive controls, text fields, and nested gesture recognizers.
- Ensure important actions remain discoverable and accessible.
- Use suitable accessibility labels and support Dynamic Type where possible.
- Avoid updating expensive interface elements on every scroll callback unless needed; optimize frequent delegate work.
- Check the safe area and content insets so that content is not hidden beneath system interface elements.
17. Practical Exercise
Exercise: Build a Scrollable Learning Profile Screen
Create a profile screen for a learning application using UIKit and Swift. The screen should contain:
- A heading titled “My Learning Profile”.
- A profile image or placeholder view.
- The learner's name and course information.
- A vertical list of at least eight learning modules.
- A progress label for each module.
- A button at the bottom to view course details.
- A scroll view that makes all content accessible on a small device.
Requirements
- Use
UIScrollView as the scrolling container.
- Use Auto Layout constraints with
contentLayoutGuide and frameLayoutGuide.
- Use a vertical stack view to arrange module rows.
- Ensure that the content width matches the scroll view's visible width.
- Test the layout on at least two simulator sizes.
- Confirm that the bottom button can be reached by scrolling.
Challenge Tasks
- Add a “Back to Top” button that scrolls to the beginning with animation.
- Display the current vertical content offset in a debug label.
- Test the interface after rotating the simulator.
- Add a text field and ensure it remains accessible when the keyboard appears.
18. Interview Questions and Answers
Q1. What is UIScrollView?
Answer: UIScrollView is a UIKit view that allows users to scroll through content larger than its visible frame. It can also support zooming when configured appropriately.
Q2. What is the difference between frame and content size?
Answer: The frame describes the scroll view's visible viewport. The content size describes the overall area through which the user can scroll when content dimensions are set explicitly.
Q3. What does contentOffset do?
Answer: It indicates the current position of the visible viewport relative to the content. It can also be changed programmatically to move to a particular location.
Q4. Why use contentLayoutGuide?
Answer: It provides layout anchors for the scrollable content area, helping Auto Layout determine the content's boundaries.
Q5. What is frameLayoutGuide?
Answer: It provides layout anchors for the scroll view's visible frame. For example, matching a content view's width to it helps create a vertical-only scrolling layout.
Q6. How do you create a vertical-only scrolling interface with Auto Layout?
Answer: Pin the content view to the scroll view's content layout guide, match its width to the frame layout guide, and ensure the content's internal constraints determine a height that can exceed the visible frame.
Q7. How do you create a horizontal scroll view?
Answer: Define the scroll view's visible frame, pin the content to the content layout guide, match the content height to the frame layout guide, and let the content width exceed the frame width.
Q8. What is UIScrollViewDelegate?
Answer: It is a protocol that provides callbacks for scrolling activity, including when scrolling begins, the offset changes, dragging ends, and deceleration finishes.
Q9. When should you use UICollectionView instead of UIScrollView?
Answer: Use a collection view for large or data-driven sets of items, grids, or flexible item layouts where reusable cells and collection-management features are useful.
Q10. Why might a scroll view fail to scroll?
Answer: The content may not exceed the visible frame, scrolling may be disabled, or the content size and Auto Layout constraints may be incomplete or incorrect.
19. Quick Revision Checklist
- Understand the purpose of
UIScrollView.
- Know the difference between the visible frame, content size, and content offset.
- Understand when to use explicit content sizing versus Auto Layout.
- Use
contentLayoutGuide to define content boundaries.
- Use
frameLayoutGuide to relate content dimensions to the visible frame.
- For vertical scrolling, normally match the content width to the frame width.
- For horizontal scrolling, normally match the content height to the frame height.
- Know the basic properties for indicators, bounce behavior, and enabled scrolling.
- Understand common
UIScrollViewDelegate methods.
- Test on different device sizes, with keyboard interaction, and after rotation.
20. Conclusion
UIScrollView is an essential UIKit component for creating interfaces that contain more content than can fit within a single screen. By understanding the visible frame, content size, content offset, and Auto Layout guides, developers can create flexible vertical and horizontal scrolling experiences.
For simple custom screens, a scroll view combined with a content view and stack view is often sufficient. For large, data-driven lists and grids, consider using UITableView or UICollectionView. A well-designed scrollable interface should be responsive, accessible, easy to navigate, and thoroughly tested on different devices.
21. Additional Learning Resources