Reputation: 1179
What I would like to achieve:
A rectangle (paper) of a given size which is draw inside a view. If it is larger than the view I would like it to be scrollable. If it is smaller than the view I would like it be centered.
A list of shapes should be drawn on top of this rectangle. If they are outside the rectangle they should not be clippd but be drawn anyway.
The scrollable area is only affected by the rect(paper) not by the shapes. So a shape outside the scrollable area does not need to be drawn.
I am using Swift2.0, auto layout and InterfaceBuilder
What I have now:
I have a custom CanvasView inside an NSScrollView.
I used this trick to center the CanvasView if the canvas size is smaller than the NSScrollView: https://stackoverflow.com/a/28154936/1533291
My CanvasView is defined like this:
class CanvasView : NSView {
var canvasSize = Vec2d(x: 100, y: 100) {
didSet {
invalidateintrinsiccontentsize()
}
}
var shapes : [MyShape] = []
override func drawRect(dirtyRect: NSRect) {
if let context = currentContext {
let offsetX = (bounds.width-CGFloat(canvasSize.x))/2.0
let offsetY = (bounds.height-CGFloat(canvasSize.y))/2.0
CGContextTranslateCTM(context, offsetX, offsetY)
CGContextSetRGBFillColor(context, 1, 1, 1, 1)
CGContextFillRect(context, CGRect(x:0,y:0, width: CGFloat(canvasSize.x), height: CGFloat(canvasSize.y)))
for shape in shapes {
shape.shape.render(context)
}
}
}
override var intrinsicContentSize : NSSize {
return NSSize(width: canvasSize.x, height: canvasSize.y)
}
}
So as you can see I draw everything centered inside the canvas view.
The problem is if one of the shapes is outside the canvas it get's clipped because drawRect can only draw inside the view's bounds.
Thats why I would like to stretch the CanvasView so it's width and height are alway equal to or greater than the size of the scrollview. But I do not know how to do it and I am not even sure if this is the most elegant approach.
Update: The answer I posted below does not work when the ScrollView is zoomable and the zoom factor is less than one. I this case the canvas is neither stretched to full size nor is it centred. I am still interested in a working solution for zoomable Scrollviews.
Upvotes: 0
Views: 341
Reputation: 1179
Update: Does not work when the ScrollView is zoomable and the zoom factor is less than 1...
After some more experimenting I found a working solution myself. The core solution is quite straightforward:
Specify the class for the custom NSView inside the Clip View (you do not need to set change the ClipView's class)
Now add two Constraints:
This is what I already tried before but it would result in InterfaceBuilder complaining the constraint definitions not being sufficient because it does not know that the alignment is done at runtime by the NSScrollView itself.
But as these two constraints are not needed at runtime you can select the option "remove at build time" for both of them
But even now InterfaceBuilder is complaining. It does not know the intrinsicSize of the customView even though it is defined in the customView class. It marks the width/height constraints as ambiguous.
Now InterfaceBuilder is happy and when running the app the customView never is smaller than the scrollView.
All the compression resistance and content hugging priorities can be left set to their defaults.
The following screenshot shows the described options in InterfaceBuilder:
Upvotes: 1