Rounded rect on NSView that clips all containing subviews
Asked Answered
F

3

21

I am creating a NSView subclass that has rounded corners. This view is meant to be a container and other subviews will be added to it. I am trying to get the rounded corners of the NSView to clip all of the subview's corners as well, but am not able to get it.

- (void)drawRect:(NSRect)dirtyRect {
    NSRect rect = [self bounds];
    NSBezierPath *path = [NSBezierPath bezierPathWithRoundedRect:rect xRadius:self.radius yRadius:self.radius];
    [path addClip];

    [[NSColor redColor] set];
    NSRectFill(dirtyRect);

    [super drawRect:dirtyRect];     
}

The red is just for example. If I add a subview to the rect, The corners are not clipped: enter image description here

How can I achieve this?

Fidel answered 23/2, 2011 at 6:3 Comment(1)
The clip in -drawRect: affects only the view's drawing and has nothing to do with the subviews that still exist in the view's entire rectangle. The drawing isn't over the subviews, it's under them. Jason's answer is about the only way to accomplish this. Use layer-backed views.Hindustan
P
0

Have you tried clipping with layers?

self.layer.cornerRadius = self.radius; self.layer.masksToBounds = YES;


Ah, sorry, somehow I've missed that you were talking about NSView, not UIView. It would be hard to clip NSView subviews in all cases because it seems that most of Cocoa standard views set their own clipping path. It might be easier to layout subviews with some paddings and avoid need for clipping.

Pyorrhea answered 23/2, 2011 at 10:40 Comment(4)
Yes. Adding theses lines, as well as [self setWantsLayer:YES], does not round the corners of the container or its contentsFidel
Ah, sorry, somehow I've missed that you were talking about NSView, not UIView. It would be hard to clip NSView subviews in all cases because it seems that most of Cocoa standard views set their own clipping path. It might be easier to layout subviews with some paddings and avoid need for clipping.Pyorrhea
I rethought my layout. Marked correct for that, but you should edit your answer to include what you said in the comment, not the incorrect layer stuff to avoid confusionFidel
I so want to upvote this answer because it helped me with my UIView.Bindweed
S
34

Using Core Animation layers will clip sublayers correctly.

In your container NSView subclass:

- (id)initWithFrame:(NSRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        self.layer = _layer;   // strangely necessary
        self.wantsLayer = YES;
        self.layer.masksToBounds = YES;    
        self.layer.cornerRadius = 10.0;    
    }    
    return self;
}
Soniasonic answered 6/10, 2011 at 15:2 Comment(3)
Note: This won't work for the special case of rounding the corners of an NSScrollView whose document view grows in size past the bounds of the NSScrollView (it appears to reset the layer clipping path once the document bounds change). However, it will work if the document view is a static size less than or equal to the scroll view size.Lord
Before calling self.wantsLayer = YES; you need to set the layer: self.layer = layer; developer.apple.com/library/mac/#documentation/Cocoa/Reference/…Leveret
@JasonFuerstenberg self.wantsLayer = YES; will automatically create a CALayer and assign it to the views layer property. There's really no reason to do this.Cavort
B
24

You can do it in the interface builder without subclassing adding User Defined Runtime Attributes"

enter image description here

Bullate answered 6/12, 2016 at 11:58 Comment(2)
Note that this only works if you don't enable the CALayer in the View Effects inspector; its settings seem to override the custom attributes.Junior
Amazing solution. I didn't know we could do that. Thanks.Lathrope
P
0

Have you tried clipping with layers?

self.layer.cornerRadius = self.radius; self.layer.masksToBounds = YES;


Ah, sorry, somehow I've missed that you were talking about NSView, not UIView. It would be hard to clip NSView subviews in all cases because it seems that most of Cocoa standard views set their own clipping path. It might be easier to layout subviews with some paddings and avoid need for clipping.

Pyorrhea answered 23/2, 2011 at 10:40 Comment(4)
Yes. Adding theses lines, as well as [self setWantsLayer:YES], does not round the corners of the container or its contentsFidel
Ah, sorry, somehow I've missed that you were talking about NSView, not UIView. It would be hard to clip NSView subviews in all cases because it seems that most of Cocoa standard views set their own clipping path. It might be easier to layout subviews with some paddings and avoid need for clipping.Pyorrhea
I rethought my layout. Marked correct for that, but you should edit your answer to include what you said in the comment, not the incorrect layer stuff to avoid confusionFidel
I so want to upvote this answer because it helped me with my UIView.Bindweed

© 2022 - 2024 — McMap. All rights reserved.