Update:
My original answer was plain wrong.
Thanks to JWWalker and Wil Shipley for making me aware of that via comments.
Here's a hopefully more helpful answer for people coming here via search:
Unlike UIScrollView
, NSScrollView
does not provide a delegate method to inform you when a view was scrolled to top/bottom.
To detect those situations, you have to enable boundsDidChange
notifications and subscribe to them.
When receiving a bounds update, you can check if the y
coordinate of the clip view bounds is 0
(= bottom), or if the top edge of the clip view bounds aligns with the document view (= top).
private func configureScrollView() {
self.scrollView.contentView.postsBoundsChangedNotifications = true
NotificationCenter.default.addObserver(self, selector: #selector(contentViewDidChangeBounds), name: NSView.boundsDidChangeNotification, object: self.scrollView.contentView)
}
@objc
func contentViewDidChangeBounds(_ notification: Notification) {
guard let documentView = scrollView.documentView else { return }
let clipView = scrollView.contentView
if clipView.bounds.origin.y == 0 {
print("bottom")
} else if clipView.bounds.origin.y + clipView.bounds.height == documentView.bounds.height {
print("top")
}
}
For scroll views that use elastic scrolling, the updates come with a short delay because the clip view seems to defer the bounds change notifications until the scroll bounce has finished.
You can use the visible rect of your NSScrollView
's contentView instead of the bounds:
- (void)boundsDidChangeNotification:(NSNotification*) notification
{
NSRect visibleRect = [[_scrollView contentView] documentVisibleRect];
NSLog(@"Visible rect:%@", NSStringFromRect(visibleRect));
NSPoint currentScrollPosition = visibleRect.origin;
}
The content view bounds don't change during scrolling, so in your original code, the bounds.origin probably always returns 0/0.
UIScrollViewDelegate
? (developer.apple.com/library/ios/documentation/uikit/reference/…) – Popeyecocoa
tag. – Popeye