Сделать NSView NOT клип-надзонами за пределами своих границ

Можно ли сделать NSView не зацепить его подзоны, которые находятся за пределами границ? На iOS я просто установил clipsToBounds моего UIView no NO. Но NSView не обладает таким свойством. Я попытался поэкспериментировать с wantsLayer, masksToBounds, wantsDefaultClipping, но все они, похоже, изменяют только обрезку метода drawRect, а не subviews.

Ответы

Ответ 1

Я смог решить это, переопределив wantsDefaultClipping для подпунктов, чтобы вернуть NO.

Ответ 2

Если вы используете автозапуск, переопределите alignmentRectInsets, чтобы развернуть область отсечения, делая ее больше прямоугольника выравнивания. Этот пример дает пространство 50 со всех сторон:

override var alignmentRectInsets: NSEdgeInsets {
    return NSEdgeInsets(top: 50.0, left: 50.0, bottom: 50.0, right: 50.0)
}

Ответ 3

После 5 часов борьбы я просто добился этого. Просто измените класс любого NSView в .storyboard или .xib на 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()
    }
}

Почему я переопределяю masksToBounds в NoClippingLayer? Потому что некоторые собственные классы AppKit изменяют это свойство всех подуровней во время выполнения без каких-либо предупреждений. Например, NSCollectionView делает это для представлений о его ячейках.

Ответ 4

Поведение вокруг этого, кажется, изменилось. Вам просто нужно установить слой вида, чтобы не маскировать границы.

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

Ответ 5

wantDefaultClipping метод работает... и родитель, и ребенок должны override хочетDefaultClipping.

Как только вы идете по этому маршруту, очистка после себя громоздка.

Здесь мое решение для прикрепления текста к 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];
   }
}

Ответ 6

Для людей, ищущих эквивалентный быстрый код:
Добавьте этот код в подкласс NSView:

override var wantsDefaultClipping:Bool{return false}//avoids clipping the view

Вам не нужно менять родителя. пока родитель имеет достаточно большую область отсечения. Но его удобно также добавить эту переменную к родительскому.

Обновление 1:

Это непростая тема, и я провел недели, исследуя это, и мое лучшее решение можно найти здесь: http://stylekit.org/blog/2015/12/24/The-odd-case-of-luck/

Обновление 2:

Чтобы увидеть приведенную выше концепцию в действии, проверьте эту статью: http://stylekit.org/blog/2015/12/30/Graphic-framework-for-OSX/

Ответ 7

Я не мог заставить любое из этих решений работать. Я думаю, вам, возможно, придется просто изменить иерархию представлений, чтобы представления не рисовали вне рамки. Вы можете создать промежуточное представление, которое не делает никакого рисунка, но имеет более крупный фрейм, чтобы обеспечить большую область.