I've created a custom segment control (Cocoa / macOS) by subclassing NSView (does not use any existing controls / buttons; it's an entirely custom view with a complex set of internal constraints) that has two modes:
- Displays all segments horizontally by default: [ segment 1 ] [ segment 2 ] [ segment 3 ]
- Displays a single segment as a drop down when all segments cannot fit in the window / current set of constraints (influenced by surrounding controls and their constraints): [ segment 1 ]
This works just fine, and I'm able to switch between / animate the two modes at runtime. However what I want to ultimately achieve is automatic expansion / compression based on the current window size (or switch between the two when the user is resizing the window). I want this control to be reusable without the window / view controller managing the switch, and trying to avoid switching between constraints based on 'rough' estimates from inside of a superview's layout call (which feels like a hack).
It seems NSSegmentControl, NSButton etc implement NSUserInterfaceCompression which should do what I am trying to achieve, however none of the methods in that protocol get called at any time during initial layout / intrinsic content size refresh / window resize etc. I also find the documentation lacking; the only useful information I found was inside the NSSegmentControl header files. The protocol seems to be exactly what I need - for the system to call the appropriate methods to determine a minimum / ideal size and ask the control to resize itself when space is at a premium.
For what it's worth, I've tried subclassing NSButton too (for various reasons, I need to stick to subclassing NSView) - however that did not trigger any of these methods either (i.e. from NSUserInterfaceCompression).
Any idea what I'm missing?
It seems
NSUserInterfaceCompressionis a dead end. For now I've reported this as feedback / bug regarding the inadequate documentation (FB9062854).The way I ended up solving this is by:
The last segment (inner
NSViewsubviews) within the control has a trailing anchor set with prioritydefaultLowto allow it to break so that the control can continue to stretchOverride
setFrameSizeand determine the best mode to display (compressed, single segment as a drop down, or all the segments if they can fit horizontally). Then callinvalidateIntrinsicContentSize()for the content size to be recomputed.Using the mode determined in the previous step, override
intrinsicContentSizeand offer the correct size (the minimum compressed version or the one where all segments can fit).This way the control wraps all of this functionality into a single
NSViewsubclass and relieves any superview / window hosting this control of setting the correct size as the window is resized.