使NSView NOT剪辑子视图超出其范围

时间:2013-07-22 16:45:08

标签: objective-c cocoa calayer nsview clip

是否可以使NSView 剪辑其超出界限的子视图?在iOS上,我只需设置clipsToBoundsUIView的{​​{1}}。但是NO没有这样的属性。我尝试使用NSViewwantsLayermasksToBounds进行试验,但所有这些似乎只会更改wantsDefaultClipping方法的剪辑,而不是子视图。

5 个答案:

答案 0 :(得分:7)

我能够通过覆盖wantsDefaultClipping个子视图来返回NO来解决此问题。

答案 1 :(得分:5)

经过5个小时的挣扎,我才刚刚实现。只需将.storyboard或.xib中的任何NSView的类更改为NoClippingView,它就不会剪切任何子视图。

class NoClippingLayer: CALayer {
        override var masksToBounds: Bool {
            set {

            }
            get {
                return false
            }
        }
    }

    class NoClippingView: OSView {
        override var wantsDefaultClipping: Bool {
            return false
        }

        override func awakeFromNib() {
            super.awakeFromNib()
            wantsLayer = true
            layer = NoClippingLayer()
        }
    }

为什么要在NoClippingLayer中覆盖masksToBounds?因为一些本机AppKit类在运行时更改了所有子层的此属性而没有任何警告。例如,NSCollectionView为其单元格的视图执行此操作。

答案 2 :(得分:1)

围绕此的行为似乎已经改变。您只需要将视图的图层设置为不遮挡边界即可。

view.wantsLayer = true
view.layer?.masksToBounds = false

答案 3 :(得分:0)

wantsDefaultClipping方法有效...父母和...孩子需要 覆盖wantsDefaultClipping。

然而,一旦你走了那条路,自己清理后很麻烦。

这是我将文本附加到NSProgressBar的解决方案:

感谢BGHUDAppKit和stackoverflow

@implementation BGHUDOverlayTextField
- (BOOL) wantsDefaultClipping { return NO; } // thanks stackoverflow.com
@end


@interface BGHUDProgressIndicator : NSProgressIndicator {

    NSBezierPath *progressPath;
    NSString *themeKey;
   NSString *LayerKey; 
   BGHUDOverlayTextField *customTitleField;
   BOOL hiding;
}

@implementation BGHUDProgressIndicator
- (BOOL) wantsDefaultClipping { return (customTitleField == nil); } // thanks stackoverflow.com
- (void) setCustomTitle: (NSMutableAttributedString *)iTitle
{
   if ( !customTitleField )
   {
      NSRect r = [self bounds];
      r.size.height += 10;
      customTitleField = [[BGHUDOverlayTextField alloc] initWithFrame:r];
      [self addSubview: customTitleField];
   }

   [customTitleField setAttributedStringValue:iTitle];
}

- (void)setHidden:(BOOL)flag
{
   if ( customTitleField && flag && !hiding )
   {
      hiding = YES;
      NSRect fr = [self bounds];
      NSRect eraseFr = fr;
      eraseFr.size = [customTitleField frame].size;
      [self displayRectIgnoringOpacity:fr];
   }
   else if ( !flag )
      hiding = NO;
   [super setHidden:flag];
}

- (void) drawRect: (NSRect)fr
{
   if ( customTitleField )
   {
      fr = [self bounds];
      NSRect eraseFr = fr;
      eraseFr.size = [customTitleField frame].size;
      [[NSColor normalSolidFill] set];
      NSRectFill( eraseFr );
      if ( hiding )
      {
         [customTitleField setAttributedStringValue:nil];
         NSRectFill( eraseFr );
         return;
      }
      [NSGraphicsContext saveGraphicsState];
      NSRectClip(fr);
   }
   [super drawRect:fr];

   if ( customTitleField )
   {
      [NSGraphicsContext restoreGraphicsState];
   }
}

答案 4 :(得分:0)

我无法使这些解决方案起作用。我认为您可能只需更改视图层次结构,以便视图不会在其框架之外绘制。您可以创建一个中间视图,该视图不会进行任何绘制,但具有更大的框架以允许更大的区域。