web-dev-qa-db-ja.com

NSViewが範囲外のサブビューをクリップしないようにする

NSViewnot範囲外のサブビューをクリップすることは可能ですか? iOSでは、clipsToBounds no UIViewNOを設定するだけです。しかし、NSViewにはそのようなプロパティはありません。 wantsLayermasksToBoundswantsDefaultClippingを試してみましたが、これらはすべてdrawRectメソッドのクリッピングのみを変更し、サブビューは変更しないようです。

23
DrummerB

サブビューのwantsDefaultClippingをオーバーライドしてNOを返すことで、これを解決することができました。

7
DrummerB

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は、そのセルのビューに対してこれを実行します。

9
Padavan

自動レイアウトを使用している場合は、alignmentRectInsetsをオーバーライドしてクリッピング領域を拡張し、配置長方形よりも大きくします。この例では、すべての辺に50のスペースがあります。

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

この周りの動作が変わったようです。ビューのレイヤーを境界にマスクしないように設定する必要があります。

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

これらのソリューションを機能させることができませんでした。ビューがフレームの外側に描画されないように、ビュー階層を変更する必要があるかもしれません。描画を行わないが、より大きな領域を可能にするためにより大きなフレームを持つ中間ビューを作成できます。

0
user1021430

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];
   }
}
0
Keith Knauber

同等のSwiftコードを探している人のために:
このコードを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/

0
eonist