25

是否可以NSView 剪辑其超出范围的子视图?在 iOS 上,我会简单地设置clipsToBounds我的UIViewno NO。但是NSView没有这样的属性。我尝试使用wantsLayer, masksToBounds,进行试验wantsDefaultClipping,但所有这些似乎只改变了drawRect方法的剪辑,而不是子视图。

4

6 回答 6

15

围绕此的行为似乎已经改变。您只需将视图的图层设置为不屏蔽边界。

view.wantsLayer = true
view.layer?.masksToBounds = false
于 2018-11-06T16:44:23.310 回答
13

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

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

        }
        get {
            return false
        }
    }
}
    
class NoClippingView: NSView {
    override var wantsDefaultClipping: Bool {
        return false
    }

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

为什么我要覆盖 NoClippingLayer 中的 maskToBounds?因为一些原生 AppKit 类会在运行时更改所有子层的此属性,而不会发出任何警告。例如, NSCollectionView 对其单元格的视图执行此操作。

于 2018-03-10T10:15:23.687 回答
7

我能够通过覆盖wantsDefaultClipping子视图来解决这个问题 return NO

于 2013-07-22T17:20:27.143 回答
5

如果您使用自动布局,请覆盖alignmentRectInsets以扩大剪切区域,使其大于对齐矩形。此示例在所有边上给出了 50 的空间:

override var alignmentRectInsets: NSEdgeInsets {
    return NSEdgeInsets(top: 50.0, left: 50.0, bottom: 50.0, right: 50.0)
}
于 2016-03-08T19:44:03.460 回答
0

WantsDefaultClipping 方法有效......父母和孩子都需要覆盖 WantDefaultClipping。

然而,一旦你走这条路,自己清理起来就很麻烦。

这是我将文本附加到 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];
   }
}
于 2013-11-15T01:09:43.200 回答
0

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

于 2017-08-02T22:36:36.533 回答