October 16, 2006
Do enough crazy visual stuff in Cocoa, and you might eventually want to manually move a UI element when an NSView changes its frame or bounds. For example, if you wanted a child window to float over a particular view in your main window. NSWindow will handle moving the child window along with the parent, but if the view you’re using as an origin can be dynamically resized, you’ll have to account for that yourself.
NSView has two useful notifications, NSViewFrameDidChangeNotification and NSViewBoundsDidChangeNotification, which are almost perfect; except for one special case. When the user shows or hides the window’s toolbar, the contents of the window will slide up or down, but you won’t receive any notifications from the NSView you’re trying to track. Of course, this is because the view’s frame and bounds didn’t really change; although the screen coordinates changed, NSView measures everything in the coordinate system of its superview (or the window’s internal coordinate system if it’s first in the view hierarchy).
The solution wasn’t obvious to me at first, but it’s actually very simple. Just register for NSWindowDidResizeNotification notifications from the window you want to track. They’ll be posted when the toolbar is shown or hidden, and you can update your UI from there. As a bonus, you might not even need notifications from the NSView anymore. If you only have one dynamically sized view in your window, the only time its frame will change is when the window changes as well.