If that may help, this is what I did to sync the vertical scroll of 2 tableViews (would be very similar):
- IBOutlets for the 2 BorderedScrollView
@IBOutlet weak var rowHeaderScrollView: NSScrollView!
@IBOutlet weak var dataScrollView: NSScrollView!
-
In override func windowDidLoad() {
dataScrollView.contentView.postsBoundsChangedNotifications = true
NotificationCenter.default.addObserver(self, selector: #selector(boundsDidChangeNotification), name: NSView.boundsDidChangeNotification, object: dataScrollView.contentView)
rowHeaderScrollView.contentView.postsBoundsChangedNotifications = true
NotificationCenter.default.addObserver(self, selector: #selector(boundsDidChangeNotification), name: NSView.boundsDidChangeNotification, object: rowHeaderScrollView.contentView)
To calculate bounds:
func calculeBounds() {
let totalHeight = dataTableView.frame.height
let headerHeight = dataTableView.headerView!.frame.height
contentUpperBound = -headerHeight
let totalScrollHeight = dataScrollView.frame.height
contentLowerBound = totalHeight - totalScrollHeight
}
- And responding to notifications:
@objc func boundsDidChangeNotification(_ notification: Notification) {
if notification.object as? NSClipView == dataScrollView.contentView {
let origin = (notification.object as! NSClipView).bounds.origin.y
rowHeaderScrollView.contentView.bounds.origin.y = origin
} else if notification.object as? NSClipView == rowHeaderScrollView.contentView {
let origin = rowHeaderScrollView.contentView.bounds.origin.y
if rowHeaderScrollView.contentView.bounds.origin.y > contentLowerBound || rowHeaderScrollView.contentView.bounds.origin.y < contentUpperBound { return }
dataScrollView.contentView.bounds.origin.y = origin
}
}
Hope that will help.