Check if a UIScrollView reached the top or bottom
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
Detecting whether a UIScrollView is at the top or bottom is mainly about comparing contentOffset with the visible bounds and insets. The only subtle part is that modern iOS layouts often include adjusted content insets, so a correct check should account for them rather than comparing against zero blindly.
Top and Bottom Are Offset Calculations
At a high level:
- top means the vertical offset is at or above the upper inset
- bottom means the offset plus visible height has reached the content height plus lower inset
In Swift, a reusable helper looks like this:
This is a better default than checking contentOffset.y <= 0, because safe areas and automatic inset adjustments can move the true visual top.
Use the Delegate Callback
The usual place to evaluate these conditions is scrollViewDidScroll.
This gives you continuous updates during user interaction, which is what you need for sticky UI behavior, infinite scrolling, or pull-to-refresh logic.
Add a Threshold for Real Apps
Exact equality is often too strict. Floating-point rounding, bounce behavior, and partial visibility make threshold checks more practical.
This is the common pattern for loading the next page of content before the user hits the exact last pixel.
Remember That Small Content Changes the Meaning
If the content is shorter than the visible area, the scroll view may effectively be both at the top and bottom at the same time. That is not a bug in the math; it is the correct interpretation of a view with nothing to scroll.
So if your logic triggers loading or animations, decide how to handle that case explicitly. Infinite scroll code often needs a guard to prevent repeated "bottom reached" triggers when the content is not yet tall enough to fill the screen.
Bounce and Insets Affect User Perception
With bouncing enabled, users can drag past the top or bottom temporarily. That means your check may become true before the scroll view visibly settles back. In some flows, that is fine. In others, you may want to wait until dragging ends or deceleration stops before acting.
Similarly, if the scroll view lives under a navigation bar or uses automatic content insets, the adjusted insets are part of what the user sees. Using raw bounds alone often produces checks that feel off by one navigation bar height.
Common Pitfalls
- Checking
contentOffset.y <= 0and ignoring adjusted top insets. - Comparing directly against
contentSize.heightwithout subtracting the visible height of the scroll view. - Triggering "bottom reached" logic repeatedly when the content is shorter than the viewport.
- Using exact pixel equality when a threshold-based check would be more stable.
- Forgetting that bounce can make top or bottom checks fire during overscroll, not just at a settled resting position.
Summary
- Use
contentOffset, visible height, and adjusted insets together to detect top and bottom correctly. - '
scrollViewDidScrollis the usual place to run the checks.' - Thresholds are often better than exact comparisons for production UI.
- Short content can make the view effectively both top and bottom at once.
- Bounce and safe-area insets affect when users perceive that the scroll view reached an edge.

