I came up with something a little different. The one above seemed a little simpler than mine, so I tried it and found that when dragging the divider, both views changed to the same size no matter which way the divider was dragged. With mine, when dragged left, the firstView gets smaller and the second view gets bigger and visa versa.
My AppDelegate.swift is the same as above.
NerdSplitViewController.swift:
import Cocoa
class NerdSplitViewController: NSViewController {
let maxWidth: CGFloat = 600
let minimumViewWidth: CGFloat = 50
let minimumViewHeight: CGFloat = 300
var firstViewWidth: CGFloat = 300
var secondViewWidth: CGFloat = 300
var mouseDown: CGFloat!
var originalFirstViewWidth: CGFloat = 300
var firstViewWidthConstraint: NSLayoutConstraint?
var secondViewWidthConstraint: NSLayoutConstraint?
var isResizing: Bool = false
func reset() {
guard childViewControllers.count == 2 else {
return
}
let firstView = childViewControllers[0].view
firstView.translatesAutoresizingMaskIntoConstraints = false
let separator = NSBox()
separator.boxType = .separator
separator.translatesAutoresizingMaskIntoConstraints = false
let secondView = childViewControllers[1].view
secondView.translatesAutoresizingMaskIntoConstraints = false
view.subviews = [firstView, separator, secondView]
let viewsDict = ["V0" : firstView, "separator" : separator, "V1" : secondView]
let metricsDict = ["minWidth" : minimumViewWidth as NSNumber,
"minHeight" : minimumViewHeight as NSNumber]
// Sets the new width of the first view
firstViewWidthConstraint?.isActive = false
firstViewWidthConstraint = firstView.widthAnchor.constraint(equalToConstant: firstViewWidth)
firstViewWidthConstraint?.isActive = true
// sets the new width of hte second view
secondViewWidthConstraint?.isActive = false
secondViewWidthConstraint = secondView.widthAnchor.constraint(equalToConstant: secondViewWidth)
secondViewWidthConstraint?.isActive = true
func addVisualFormatConstraints(_ visualFormat: String) {
let constraints = NSLayoutConstraint.constraints(withVisualFormat: visualFormat,
options: [],
metrics: metricsDict,
views: viewsDict)
NSLayoutConstraint.activate(constraints)
}
// the visual format for the second view needed to edited so as not to be equal to the first view.
addVisualFormatConstraints("H:|[V0(>=minWidth)][separator(==1)][V1(>=minWidth)]|")
addVisualFormatConstraints("V:|[V0]|")
addVisualFormatConstraints("V:|[separator(>=minHeight)]|")
addVisualFormatConstraints("V:|[V1]|")
}
override func loadView() {
view = NSView()
reset()
}
override func insertChildViewController(_ childViewController: NSViewController, at index: Int) {
super.insertChildViewController(childViewController, at: index)
if isViewLoaded {
reset()
}
}
override func removeChildViewController(at index: Int) {
super.removeChildViewController(at: index)
if isViewLoaded {
reset()
}
}
// MARK: - Mouse Events
override func mouseDown(with event: NSEvent) {
let locationX = event.locationInWindow.x
// This will allow clicks within +/- 5 of the separator
if (locationX <= firstViewWidth + 5 && locationX >= firstViewWidth - 5) {
mouseDown = event.locationInWindow.x
isResizing = true
}
}
override func mouseDragged(with event: NSEvent) {
if isResizing {
// The firstWidthView is either the minimumViewWidth or the x location in the window, whichever is greater
// The secondViewWidth is either the minimumViewWidth or the lesser of maxWidth or
// the secondViewwidth plus the difference of x in the firstViewWindow.
firstViewWidth = max(minimumViewWidth, event.locationInWindow.x)
secondViewWidth = max(minimumViewWidth,
min(maxWidth, secondViewWidth + (originalFirstViewWidth - firstViewWidth)))
reset()
}
}
override func mouseUp(with event: NSEvent) {
originalFirstViewWidth = firstViewWidth
isResizing = false
}
}