Skip to content

Instantly share code, notes, and snippets.

@blundgren
Created March 11, 2016 17:56
Show Gist options
  • Save blundgren/a68d70f792f138bae23b to your computer and use it in GitHub Desktop.
Save blundgren/a68d70f792f138bae23b to your computer and use it in GitHub Desktop.
An NSClipView subclass which performs drag-scrolling.
class DraggableClipView: NSClipView
{
private var clickPoint: NSPoint!
private var originalOrigin: NSPoint!
override func mouseDown(event: NSEvent) {
clickPoint = event.locationInWindow
originalOrigin = bounds.origin
}
override func mouseDragged(event: NSEvent) {
// Account for a magnified parent scrollview.
let scale = (superview as? NSScrollView)?.magnification ?? 1.0
let newPoint = event.locationInWindow
let newOrigin = NSPoint(x: originalOrigin.x + (clickPoint.x - newPoint.x) / scale,
y: originalOrigin.y + (clickPoint.y - newPoint.y) / scale)
let constrainedRect = constrainBoundsRect(NSRect(origin: newOrigin, size: bounds.size))
scrollToPoint(constrainedRect.origin)
superview?.reflectScrolledClipView(self)
}
override func mouseUp(event: NSEvent) {
clickPoint = nil
}
}
@Hucent
Copy link

Hucent commented Jul 15, 2020

It saved my life. Thank you so much.

@albbadia
Copy link

Works like a charm. Some modifications are needed in order to adapt it to Swift 5 but Xcode will help you with that :D

Copy link

ghost commented Mar 29, 2022

Really awesome! Thank you a lot for that!

For my needs I modified it for Swift 5 and inverted the Y axis.

class DraggableClipView: NSClipView {

    private var clickPoint: NSPoint!
    private var originalOrigin: NSPoint!

    override func mouseDown(with event: NSEvent) {
        clickPoint = event.locationInWindow
        originalOrigin = bounds.origin
    }

    override func mouseDragged(with event: NSEvent) {

        let scale = (superview as? NSScrollView)?.magnification ?? 1.0

        let newPoint = event.locationInWindow

        let newOrigin = NSPoint(x: originalOrigin.x + (clickPoint.x - newPoint.x) / scale,
                                y: originalOrigin.y - (clickPoint.y - newPoint.y) / scale)

        let constrainedRect = constrainBoundsRect(NSRect(origin: newOrigin, size: bounds.size))

        scroll(to: constrainedRect.origin)

        superview?.reflectScrolledClipView(self)
    }

    override func mouseUp(with _: NSEvent) {
        clickPoint = nil
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment