I’m continuing work on my mac project, which involves a scalable document that can be embedded in an NSScrollView. I recently wanted to add orientation to the set of valid transformations. While I’m sure there are more generic solutions that involve setting a composite affine transformation on the underlying CALayer, I wanted something that I could implement in an hour or so. I ran into some issues that I thought I’d write about in hopes of saving other people some time.
When coding against the SDK for OS X Lion, NSView has a
setFrameCenterRotation:
selector, which is very convenient for
rotating about the center of the view. If you need to run against
older versions of OS X, you can use a combination of setFrameOrigin:
and setFrameRotation:
to accomplish the same thing. These rotations
don’t affect the internal coordinate system of the NSView, but change
its frame in the superview – also very convenient when it comes to
performing layout in the rotated view.
I experimented with these for my document view’s transformations and
found some quirks. Firstly, I tried to simply rotate the
NSScrollView’s documentView
. From my previous post, this is the
HostView
object. That didn’t go quite as well as I had hoped: the
rotation occurred around the incorrect locus, and the scroll view got
very confused about positioning. When I performed the rotation, the
document would jump to an odd place, and then when I moved the scroll
bars, the document would jump back to the origin.
After that, I attempted to rotate the _docView
inside the HostView
object. Success! At least, initial success: while the rotation
occurred and the document stayed stable inside the scroll view, the
dimensions of the HostView
object stayed the same and the _docView
was positioned incorrectly. I found that the
NSViewFrameDidChangeNotification
was still being raised. When I
analyzed the newly calculated frame for the HostView
, I found the
width and height were the same as the original, when it should have
been changed.
Changing the code in updateFrame:
to detect the _docView
in
landscape orientation and transforming the frame appropriately makes
the scroll view recalculate its scroll extents correctly. There’s
still the problem of the incorrectly positioned document. I’m not
sure why Cocoa does this, but when calculating the frame for a
rotation, the view would consistently get shifted by a size
proportional to the size of the view. I had to manually adjust the
frame after the rotation had adjusted it.
After all is said and done, the new code looks like this.