是否可以制作
NSView
not 剪辑超出边界的子视图?在 iOS 上,我只需将我的 clipsToBounds
中的 UIView
设置为不 NO
。但NSView
不具备这样的性质。我尝试尝试使用 wantsLayer
、masksToBounds
、wantsDefaultClipping
,但所有这些似乎只改变 drawRect
方法的剪辑,而不是子视图。
围绕此的行为似乎已经改变。您只需将视图的图层设置为不遮盖边界即可。
view.wantsLayer = true
view.layer?.masksToBounds = false
经过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中的masksToBounds?因为某些原生 AppKit 类会在运行时更改所有子层的此属性,而不会发出任何警告。例如,NSCollectionView 对其单元格的视图执行此操作。
我能够通过覆盖子视图的
wantsDefaultClipping
来返回NO
来解决这个问题。
如果您使用自动布局,请覆盖
alignmentRectInsets
以扩展剪切区域,使其大于对齐矩形。此示例给出了所有边均为 50 的空间:
override var alignmentRectInsets: NSEdgeInsets {
return NSEdgeInsets(top: 50.0, left: 50.0, bottom: 50.0, right: 50.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];
}
}
我无法让这些解决方案发挥作用。我认为您可能必须更改视图层次结构,以便视图不会在框架之外绘制。您可以创建一个不执行任何绘图但具有更大框架以允许更大区域的中间视图。
NSView
有一个新属性:clipsToBounds,类似于 iOS的
UIView
上的属性。
view.clipsToBounds = true
[view setClipsToBounds:YES];