Trying to create a custom NSSlider
. Overriding the drawKnob()
method of the NSSliderCell
changes the knob's appearance but doing this somehow disconnects the link between the knob's position and user interactions with the slider.
In the objective C example that is often referenced (https://github.com/lucasderraugh/LADSlider) it looks like when you override drawKnob()
you then need to explicitly deal with the startTracking
method, but I haven't found a solution that works for me - at the moment I am just setting the cell's startTracking 'at' property to the current value of the slider, but not sure what the right approach is.
Quite a few examples include an NSCoder argument in the cell's custom initialiser - I don't understand why, but maybe this has something to do with ensuring a connection between the display of the knob and the actual slider value?
import Cocoa
class ViewController: NSViewController {
var seekSlider = NSSlider()
var seekSliderCell = SeekSliderCell()
override func viewDidLoad() {
super.viewDidLoad()
seekSlider = NSSlider(target: self, action: #selector(self.seek(_:)))
seekSlider.cell = seekSliderCell
seekSlider.cell?.target = self
seekSlider.cell?.action = #selector(self.seek(_:))
seekSlider.isEnabled = true
seekSlider.isContinuous = true
view.addSubview(seekSlider)
}
@objc func seek(_ sender: NSObject) {
let val = seekSlider.cell?.floatValue
let point = NSPoint(x: Double(val!), y: 0.0)
seekSlider.cell?.startTracking(at: point, in: self.seekSlider)
}
}
class SeekSliderCell: NSSliderCell {
// required init(coder aDecoder: NSCoder) {
// super.init(coder: aDecoder)
// }
override func drawKnob() {
let frame = NSRect(x: 0.0, y: 6.0, width: 20.0, height: 10.0)
let c = NSColor(red: 0.9, green: 0.0, blue: 0.6, alpha: 1.0)
c.setFill()
NSBezierPath.init(roundedRect: frame, xRadius: 3, yRadius: 3).fill()
}
override func startTracking(at startPoint: NSPoint, in controlView: NSView) -> Bool {
return true
}
}
The documentation of drawKnob()
states:
Special Considerations If you create a subclass of NSSliderCell, don’t override this method. Override drawKnob(_:) instead.
Instead of
func drawKnob()
override
func drawKnob(_ knobRect: NSRect)
Example:
class ViewController: NSViewController {
var seekSlider = NSSlider()
var seekSliderCell = SeekSliderCell()
override func viewDidLoad() {
super.viewDidLoad()
seekSlider = NSSlider(target: self, action: #selector(self.seek(_:)))
seekSlider.cell = seekSliderCell
seekSlider.cell?.target = self
seekSlider.cell?.action = #selector(self.seek(_:))
seekSlider.isEnabled = true
seekSlider.isContinuous = true
view.addSubview(seekSlider)
}
@objc func seek(_ sender: NSObject) {
let val = seekSlider.cell?.floatValue
print("\(String(describing: val))")
}
}
class SeekSliderCell: NSSliderCell {
override func drawKnob(_ knobRect: NSRect) {
var frame = NSRect(x: 0.0, y: 6.0, width: 20.0, height: 10.0)
frame.origin.x = knobRect.origin.x + (knobRect.size.width - frame.size.width) / 2
frame.origin.y = knobRect.origin.y + (knobRect.size.height - frame.size.height) / 2
let c = NSColor(red: 0.9, green: 0.0, blue: 0.6, alpha: 1.0)
c.setFill()
NSBezierPath.init(roundedRect: frame, xRadius: 3, yRadius: 3).fill()
}
}