Callbacks When an NSScrollView is Scrolled?
Asked Answered
A

6

48

I'm making a Mac app which needs to know when the user is scrolling the NSScrollView, however, I can't find any methods like UIScrollView, which has the following delegate methods:

– scrollViewDidScroll:
– scrollViewWillBeginDragging:
– scrollViewDidEndDragging:willDecelerate:
– scrollViewShouldScrollToTop:
– scrollViewDidScrollToTop:
– scrollViewWillBeginDecelerating:
– scrollViewDidEndDecelerating:

Can I have the similar delegate methods for the App Kit? Thanks in advance.

Kai.

Africa answered 2/3, 2011 at 15:2 Comment(0)
P
79

You can monitor a scroll view's changes by monitoring the bounds of it's content view. First set the content view to post its changes with

[contentView setPostsBoundsChangedNotifications:YES];

Then register as an observer of those notifications with

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(boundsDidChange:) name:NSViewBoundsDidChangeNotification object:contentView]; 
Predecease answered 2/3, 2011 at 15:34 Comment(2)
Note that his observer is also triggered when the scrolling is performed in code.Buckra
How do I know if the scroll has ended?Samekh
S
11

Update for Swift 4:

scrollView.contentView.postsBoundsChangedNotifications

Also the call is:

NotificationCenter.default.addObserver(self,
                                       selector: #selector(boundsChange),
                                       name: NSView.boundsDidChangeNotification,
                                       object: scrollView.contentView)

Edit: the collection in mac doesn't inherit from scrollview. updated properly

Stung answered 22/3, 2018 at 22:14 Comment(2)
Upvoted too soon, it actually does not work as is. CollectionView is not a scroll view.Gev
apologies, I copy pasted but this is really not the collection but a the scrollview content viewStung
H
4

Had the same problem recently... To somewhat emulate deceleration callbacks it is possible to override

-(void) scrollWheel:(NSEvent *)theEvent 

of NSScrollView class, but then check theEvent.momentumPhase instead of theEvent.phase for event phases.

Harbin answered 12/12, 2012 at 8:4 Comment(0)
G
4

Adding to @Sean Rich answer.

The contentView is the NSClipView between the NSScrollView and NSCollectionView.

Picture of clip view from the Storyboard

For this to work, both the ClipView needs to be set to postsBoundsChangedNotifications and should be passed in the notification object.

self.clipView.postsBoundsChangedNotifications = true

NotificationCenter.default.addObserver(self,
                                       selector: #selector(collectionViewDidScroll(notification:)),
                                       name: NSView.boundsDidChangeNotification,
                                       object: self.clipView)
Gev answered 6/5, 2018 at 3:45 Comment(3)
Should there also be a subsequent removeObserver call? when the class is deInit ?Tristantristas
@eonist Good question. You do not need to remove observer in this call. From Apple: "If your app targets iOS 9.0 and later or macOS 10.11 and later, you do not need to unregister an observer that you created with this function" developer.apple.com/documentation/foundation/notificationcenter/…Gev
thanks, almost like a callback then. You don't have to deregister them eitherTristantristas
P
0

my two cents for swift 4.2 OSX:

....

if let clipView = self.collectionView.superview, let sv = clipView.superview as? NSScrollView{

        let contentView = sv.contentView
        contentView.postsBoundsChangedNotifications = true

        NotificationCenter.default.addObserver(self,
                                               selector: #selector(collectionViewDidScroll(notification:)),
                                               name: NSView.boundsDidChangeNotification,
                                               object: clipView)
}








 //MARK: scrollview observer:

    @objc func collectionViewDidScroll(notification: Notification){

    }
Profiteer answered 26/3, 2019 at 10:28 Comment(0)
U
0

Use the following:

NSScrollViewWillStartLiveScrollNotification
NSScrollViewDidLiveScrollNotification
NSScrollViewDidEndLiveScrollNotification

NSNotificationCenter.defaultCenter().addObserver(
    self,
    selector: #selector(scrollViewDidScroll(_:)),
    name: NSScrollViewDidLiveScrollNotification,
    object: scrollView
)
Useful answered 25/8, 2022 at 19:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.