UIScrollView
scrolling detection
iOS development
Swift programming
mobile app development

How to detect when a UIScrollView has finished scrolling

Interview Questions practice on Codemia

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

Browse interview questions

Introduction

There is no single UIScrollView delegate method that means "all scrolling is done" in every case. The correct completion signal depends on whether scrolling ended after a drag, after deceleration, or after a programmatic animated scroll.

Why One Callback Is Not Enough

A scroll view can stop moving in several different ways:

  • the user drags and releases, and the view stops immediately
  • the user drags and releases, and momentum continues with deceleration
  • the app scrolls the view programmatically with animation

UIKit reports those paths through different delegate methods. That is why reliable code usually routes several delegate callbacks into one shared "scroll finished" handler.

A Reliable Delegate Pattern

The most practical pattern is to implement the three end-state callbacks and forward all of them to one method.

swift
1import UIKit
2
3final class ViewController: UIViewController, UIScrollViewDelegate {
4    @IBOutlet private weak var scrollView: UIScrollView!
5
6    override func viewDidLoad() {
7        super.viewDidLoad()
8        scrollView.delegate = self
9    }
10
11    private func handleScrollDidFinish() {
12        print("Finished at offset: \(scrollView.contentOffset)")
13    }
14
15    func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
16        if !decelerate {
17            handleScrollDidFinish()
18        }
19    }
20
21    func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
22        handleScrollDidFinish()
23    }
24
25    func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) {
26        handleScrollDidFinish()
27    }
28}

This covers the common cases cleanly:

  • 'scrollViewDidEndDragging handles the no-deceleration case'
  • 'scrollViewDidEndDecelerating handles momentum after release'
  • 'scrollViewDidEndScrollingAnimation handles animated programmatic scrolling'

Why scrollViewDidEndDragging Alone Is Wrong

Many developers start with scrollViewDidEndDragging, which is only half right. If the user releases the scroll view and it keeps moving, the drag has ended but the scroll has not.

That is exactly why the method includes the willDecelerate flag.

swift
1func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
2    if decelerate {
3        print("User stopped dragging, but scrolling is still continuing")
4    } else {
5        print("Scrolling is fully finished")
6    }
7}

If decelerate is true, the actual end point comes later in scrollViewDidEndDecelerating.

Why scrollViewDidScroll Is Not a Completion API

scrollViewDidScroll fires whenever the content offset changes. It is ideal for live effects such as parallax, sticky headers, progress indicators, and lazy loading. It is not a dependable "done" signal.

Trying to detect the end by comparing the last few offsets inside scrollViewDidScroll is fragile. Small layout adjustments, bounce behavior, or nested scrolling can all produce extra callbacks that make the logic noisy.

If your goal is truly "run code when motion has stopped," UIKit already gives you the right end-of-motion hooks. Use those rather than building a timing heuristic around offset changes.

Programmatic Scrolling Is Easy to Forget

A lot of implementations work for manual drags and then fail when the app scrolls to a target offset in code.

swift
scrollView.setContentOffset(CGPoint(x: 0, y: 400), animated: true)

In that situation, scrollViewDidEndDragging and scrollViewDidEndDecelerating may never be called because no drag occurred. The right completion callback is scrollViewDidEndScrollingAnimation.

If your app auto-scrolls to validation errors, selected content, or anchored sections, you need this path covered.

Flags Can Help with State Checks

Sometimes you do not need a callback at all. You may just want to know the current state.

swift
if !scrollView.isDragging && !scrollView.isDecelerating && !scrollView.isTracking {
    print("The scroll view is idle")
}

These properties are useful in layout or interaction code, but they are best treated as state inspection, not as a replacement for completion callbacks. The delegate methods remain the cleanest place to react exactly once when scrolling ends.

Zooming Is a Separate Completion Family

If the real requirement is "detect when the user stops changing what is visible," remember that zooming is reported through different delegate methods. For example, zoom completion belongs in scrollViewDidEndZooming(_:with:atScale:), not in the scroll-end callbacks above.

That matters in image viewers and canvas-style apps where both panning and zooming exist. Treat them as related but separate event families.

Common Pitfalls

One common mistake is listening only to scrollViewDidEndDecelerating, which misses the case where dragging ends without momentum. Another is listening only to scrollViewDidEndDragging, which fires too early when deceleration continues.

A third issue is forgetting programmatic animated scrolling. The code looks correct during manual testing and then fails when the app scrolls to a location on its own.

Finally, avoid inventing completion detection by polling offsets in scrollViewDidScroll. It is harder to reason about and less reliable than the dedicated delegate callbacks UIKit already provides.

Summary

  • There is no single universal end-of-scroll callback for every scrolling path.
  • Combine scrollViewDidEndDragging, scrollViewDidEndDecelerating, and scrollViewDidEndScrollingAnimation.
  • Use the willDecelerate flag to distinguish between "drag ended" and "scroll ended."
  • Do not treat scrollViewDidScroll as a completion API.
  • Handle zoom-end callbacks separately if the view supports zooming.

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.