How do you implement zoom/scale in a Cocoa AppKit-application (i.e. not maximizing the window but scaling the window and all its subviews)? I think it's called zoomScale in iOS. Can it be done using Core Animations or Quartz 2D (e.g. CGContextScaleCTM
) or am I forced to implement it manually in all my NSViews, NSCells, etc?

- 4,037
- 2
- 35
- 44
1 Answers
Each NSView has a bounds and frame, the frame is the rectangle that describes a view's placement within its superview's bounds. Most views have a bounds with a zero origin, and a size that matches their frame size, but this doesn't have to be the case. You can change the relationship of a view's bounds and frame to scale and translate both custom drawing and subviews. When you change the bounds of a view, it also affects the drawing of descendant views recursively.
The most straightforward way to change the bounds of a view is with -[NSView scaleUnitSquareToSize:]. In one of your views, try calling [self scaleUnitSquareToSize:NSMakeSize(2.0, 2.0)], and you should see the size of everything inside of it appear to be double.
Here's an example. Create a XIB file with a window containing a custom view, and a button. Set the custom view's custom class to MyView. Connect the button's action to the view's doubleSize: action. Build and run and hit the button. The red square in the custom view should double in size with each press.
/// MyView.h
@interface MyView : NSView {
}
- (IBAction)doubleSize:(id)sender;
@end
/// MyView.m
@implementation MyView
- (IBAction)doubleSize:(id)sender {
[self scaleUnitSquareToSize:NSMakeSize(2.0, 2.0)];
/// Important, changing the scale doesn't invalidate the display
[self setNeedsDisplay:YES];
}
- (void)drawRect:(NSRect)dirtyRect {
NSSize squareSize = NSMakeSize(8, 8);
NSRect square = NSMakeRect([self bounds].size.width / 2 - squareSize.width / 2,
[self bounds].size.height / 2 - squareSize.height / 2,
squareSize.width,
squareSize.height);
[[NSColor redColor] set];
NSRectFill(square);
}
@end

- 14,237
- 1
- 47
- 51
-
I'm trying to make this work for a view that has a lot of subviews. The view I'm applying it to is scaling, but the subviews are staying the same size. Are they supposed to scale as well? – DougC Jan 31 '12 at 15:46
-
I would expect the area of the screen they occupy to change size, but their individual frame rectangles should remain unchanged. – Jon Hess Jan 31 '12 at 20:58
-
What I'm seeing is that the visual size of the sub views remains unchanged, even as the size of the view I'm scaling grows or shrinks. – DougC Jan 31 '12 at 21:38
-
Is it possible that the fact that the subviews are backed by layers would make a difference? – DougC Jan 31 '12 at 21:39
-
I've tried turning off layers for the view hierarchy and, indeed, the re-sizing starts to perform better. I still have a number of issues, but I think they're related to the way my views render themselves. – DougC Feb 06 '12 at 16:11
-
Won't zooming in this way zoom with respect to the default origin (lower left corner) -- how would we get zooming to be with respect to the mouse location? – CodeKingPlusPlus Feb 20 '16 at 06:24
-
This answer works. However: If you zoom/scale the NSView and one of the SubViews is layerbacked. you need to change the contentScale of that layer appropriately. Zoom 2x on a retina screen: (2x2=4) Zoom 4x on a retina screen: (2x2=4) etc. Or else your drawing will become pixelated. – Sentry.co Apr 24 '16 at 16:49