NSScrollView detect scroll position

烈酒焚心 提交于 2019-12-04 15:35:00

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.

if (_scrollView.verticalScroller.floatValue > 0.9)
{
    // bottom
    // do something
}

if you want to detect after scroll ended. @thomas's answer is detect when view is scrolling

  NotificationCenter.default.addObserver(
                self,
                selector: #selector(scrollViewDidScroll),
                name:NSScrollView.didLiveScrollNotification,
                object: scrollView
            )



  @objc func scrollViewDidScroll (notification: NSNotification) {

        guard let documentView = scrollView.documentView else { return }

        let clipView = scrollView.contentView
        if clipView.bounds.origin.y == 0 {
            print("top")

        } else if clipView.bounds.origin.y + clipView.bounds.height == documentView.bounds.height {

            print("bottom")

}
    }
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!