NSViewの背景色を変更する最良の方法


149

私は変更するための最良の方法を探していますbackgroundColorのをNSView。また、に適切なalphaマスクを設定できるようにしたいと考えていNSViewます。何かのようなもの:

myView.backgroundColor = [NSColor colorWithCalibratedRed:0.227f 
                                                   green:0.251f 
                                                    blue:0.337 
                                                   alpha:0.8];

私はそれNSWindowがこの方法を持っていることに気づき、私はNSColorWheel、またはNSImageバックグラウンドオプションの大ファンではありませんが、それらが最善であれば、喜んで使用します。

回答:


134

ええ、あなた自身の答えは正しかった。Cocoaメソッドを使用することもできます。

- (void)drawRect:(NSRect)dirtyRect {
    // set any NSColor for filling, say white:
    [[NSColor whiteColor] setFill];
    NSRectFill(dirtyRect);
    [super drawRect:dirtyRect];
}

Swiftの場合:

class MyView: NSView {

    override func draw(_ dirtyRect: NSRect) {
        super.draw(dirtyRect)

        // #1d161d
        NSColor(red: 0x1d/255, green: 0x16/255, blue: 0x1d/255, alpha: 1).setFill()
        dirtyRect.fill()
    }

}

18
NSRectFillNSCompositeCopy塗りつぶしに使用するため、背後にあるものはすべて上書きされます。祖先ビューの上に合成されません。部分的に(または完全に)透明な色で塗りつぶすには、操作でNSRectFillUsingOperation developer.apple.com/mac/library/documentation/Cocoa/Reference/…を使用NSCompositeSourceOverます。
Peter Hosey

ああ、それは理にかなっています。NSRectFillを試しましたが、透明度が機能しませんでした。Cocoa TouchからCocoaに来て、いくつかの点でCocoa Touchフレームワークがより完全である(!)ことに驚いています。NSWindowやUIViewのようにbackgroundColorを設定できるNSViewのクラス拡張を作成することを考えていましたが、drawRectを拡張でオーバーライドできないと思います。
BadPirate

すみません、透明部分は見逃してしまいました。ええ、ココアタッチは多くのことを簡単にします。Cocoaタッチも使用している場合は、移植性が高いため、実際には自分の答えがより優れています。
mohsenr

わかりません。これはビューの上に白い色を描画しています。試したところです。背景色についての質問ではなかったのですか?
動脈瘤2013

@Patrick-super drawRect :)を呼び出す必要がある場合があります。または、背景の上に描画されるはずのものがある場合は、それらがNSRectFill呼び出しの後にあることを確認してください。
BadPirate 2013

116

簡単で効率的なソリューションは、Core Animationレイヤーをバッキングストアとして使用するようにビューを構成することです。次に、を使用-[CALayer setBackgroundColor:]して、レイヤーの背景色を設定できます。

- (void)awakeFromNib {
   self.wantsLayer = YES;  // NSView will create a CALayer automatically
}

- (BOOL)wantsUpdateLayer {
   return YES;  // Tells NSView to call `updateLayer` instead of `drawRect:`
}

- (void)updateLayer {
   self.layer.backgroundColor = [NSColor colorWithCalibratedRed:0.227f 
                                                          green:0.251f 
                                                           blue:0.337 
                                                          alpha:0.8].CGColor;
}

それでおしまい!


6
注意:アプリケーションで使用しているWebViewを非常に独創的な方法で呼び出しsetLayer:たり、setWantsLayer:壊したりしてください。(別のウィンドウでも...)
rluba

1
メソッドsetWantsLayer:で定義されています:レイヤー付きビューを使用するときは、レイヤーと直接対話しないでください。呼び出されるタイミングsetWantsLayer:setLayer:呼び出される順序は重要です。
ステファン

レイヤーを設定するべきではありませんが、それでもこれを実現できます。ColoredViewをobjc.io/issues/14-mac/appkit-for-uikit-developersで
Clafou

80

ストーリーボード愛好家の方は、コードを一切必要しない方法をご紹介します

NSBoxNSViewにサブビューとして追加し、NSViewと同じようにNSBoxのフレームを調整します。

ストーリーボードまたはXIBで、タイトルの位置を[なし]に、ボックスタイプを[ カスタム]に、ボーダータイプを[なし]に、ボーダーの色を好きなように変更します。

ここにスクリーンショットがあります:

ここに画像の説明を入力してください

これが結果です:

ここに画像の説明を入力してください


NSBoxの使用は私にとってはうまくいきました。レイヤー付きのビューに切り替えると再描画の問題が発生しましたが、ボックスでは発生しませんでした。
Henrik

4
これは、ドキュメントにあるべき優れたシンプルなソリューションです
UKDataGeek

これはNSPopoverの三角形に色を付けますか?
Ribena

私が持っているのは後悔しているだけです。
orion elenzil

33

最初にWantsLayerをYESに設定すると、レイヤーの背景を直接操作できます。

[self.view setWantsLayer:YES];
[self.view.layer setBackgroundColor:[[NSColor whiteColor] CGColor]];

26

私がそれを行う方法を理解したと思います:

- (void)drawRect:(NSRect)dirtyRect {
    // Fill in background Color
    CGContextRef context = (CGContextRef) [[NSGraphicsContext currentContext] graphicsPort];
    CGContextSetRGBFillColor(context, 0.227,0.251,0.337,0.8);
    CGContextFillRect(context, NSRectToCGRect(dirtyRect));
}

ありがとう。dirtyRectをCGRectに変換する必要がありました。最後の行を修正してCGContextFillRect(context, NSRectToCGRect(dirtyRect));、回答を編集できますか?
ロス

1
かつては無料で橋を架けていました:/
BadPirate

6
64ビットまたはiOS用にビルドする場合、または64ビットのような32ビットをビルドする場合、NSRectはCGRectの別の言い方です。ただし、そうでない場合、これらは独立した構造体であり、同じメンバーで構成されていても、オブジェクト(「isa」ポインタを持つ構造体)のみを指す用語であるため、「フリーダイヤルでブリッジ」することはできません。およびポインタを使用して渡されますが、ジェネリック構造には渡されません。
ラファエルシュヴァイケルト

drawRectを使用すると、追加の描画時間などが発生します。10.8以降では、CALayerがより良いソリューションです。
トムアンデルセン

22

私はこれらすべての答えを調べましたが、残念ながらどれもうまくいきませんでした。しかし、私はこの非常にシンプルな方法を見つけました。

myView.layer.backgroundColor = CGColorCreateGenericRGB(0, 0, 0, 0.9);

8
NSViewsには常にレイヤーがあるとは限らないことに注意してください。その場合、これは何もしません。Ioretoparisiの回答を参照してください。
Kalle

3
コントローラのviewDidLoadメソッド(self.myCustomView用)でこのコードを実行するために多くの時間を費やしました。代わりにviewWillAppearメソッドを使用する必要があることがわかりました。
サーフライダー2015

21

編集/更新:Xcode 8.3.1•Swift 3.1

extension NSView {
    var backgroundColor: NSColor? {
        get {
            guard let color = layer?.backgroundColor else { return nil }
            return NSColor(cgColor: color)
        }
        set {
            wantsLayer = true
            layer?.backgroundColor = newValue?.cgColor
        }
    }
}

使用法:

let myView = NSView(frame: NSRect(x: 0, y: 0, width: 100, height: 100))
print(myView.backgroundColor ?? "none")     //  NSView's background hasn't been set yet = nil
myView.backgroundColor = .red               // set NSView's background color to red color
print(myView.backgroundColor ?? "none")
view.addSubview(myView)

私はこれが最もクリーンなソリューションだと思いますが、Objc.ioの人々がここで作成したステートメントについて心配しています:objc.io/issues/14-mac/appkit-for-uikit-developers -"...対話しようとするべきではありませんAppKitがこれらのレイヤーを所有しているため、レイヤーを直接使用します。」何が問題になるかわかりません。いずれにせよ、私は自分のコードでこのソリューションを採用しています。
Kevin Sliech、2016年

7

最適なソリューション:

- (id)initWithFrame:(NSRect)frame
{
    self = [super initWithFrame:frame];
    if (self)
    {
        self.wantsLayer = YES;
    }
    return self;
}

- (void)awakeFromNib
{
    float r = (rand() % 255) / 255.0f;
    float g = (rand() % 255) / 255.0f;
    float b = (rand() % 255) / 255.0f;

    if(self.layer)
    {
        CGColorRef color = CGColorCreateGenericRGB(r, g, b, 1.0f);
        self.layer.backgroundColor = color;
        CGColorRelease(color);
    }
}

へへ。起動するたびにランダムな背景色を使用したい場合に有効ですが、描画
矩形

BGカラーを描画するだけの場合は、「drawRect:」をオーバーライドするために何が必要か
Nagaraj

ええ、トップの回答であるstackoverflow.com/a/2962882/285694がその反応を示しています。-私の質問は、実際に私はこの1つにチェックを与えたので、アルファチャンネルを持つことが必要stackoverflow.com/a/2962839/285694を技術的には、この質問は(あなたはNSWindowのでできるように)アルファチャンネルでNSViewの上の背景を設定することについてです- -しかし、私は色を設定する方法だけを探して多くの人がここに来ると思います(したがって、最初の答えがより人気があります)。
BadPirate 2013年

6

Swiftの場合:

override func drawRect(dirtyRect: NSRect) {

    NSColor.greenColor().setFill()
    NSRectFill(dirtyRect)

    super.drawRect(dirtyRect)
}

5

NSViewのサブクラスであるNSBoxを使用すると、簡単にスタイルを設定できます

スウィフト3

let box = NSBox()
box.boxType = .custom
box.fillColor = NSColor.red
box.cornerRadius = 5

NSBoxには三角形の部分もあるため、NSPopoverの場合は役に立ちません。
AnaghSharma

5

間違いなく最も簡単な方法であり、カラーセットアセットとも互換性があります。

スウィフト

view.setValue(NSColor.white, forKey: "backgroundColor")

Objective-C

[view setValue: NSColor.whiteColor forKey: "backgroundColor"];

インターフェースビルダー

backgroundColorタイプのユーザー定義属性をインターフェースビルダーに追加しますNSColor


これは文書化されていない動作に依存しているため、将来のバージョンのAppKitで引き続き作業する場合は回避する必要があります。
nschmidt

3

私は以下をテストしましたが、それは私のために(Swiftで)動作しました:

view.wantsLayer = true
view.layer?.backgroundColor = NSColor.blackColor().colorWithAlphaComponent(0.5).CGColor

これを行った後、ビューの上に画像を配置しましたか?または、NSImageViewの代わりにNSViewを使用しましたか?
justColbs

3

Swift 3では、それを行う拡張機能を作成できます。

extension NSView {
    func setBackgroundColor(_ color: NSColor) {
        wantsLayer = true
        layer?.backgroundColor = color.cgColor
    }
}

// how to use
btn.setBackgroundColor(NSColor.gray)


1

迅速にNSViewをサブクラス化してこれを行うことができます

class MyView:NSView {
    required init?(coder: NSCoder) {
        super.init(coder: coder);

        self.wantsLayer = true;
        self.layer?.backgroundColor = NSColor.redColor().CGColor;
    }
}

1
Swift 4.2 Xcode 10 self.layer?.backgroundColor = NSColor.red.cgColor
brian.clear

1

小さな再利用可能なクラス(Swift 4.1)

class View: NSView {

   var backgroundColor: NSColor?

   convenience init() {
      self.init(frame: NSRect())
   }

   override func draw(_ dirtyRect: NSRect) {
      if let backgroundColor = backgroundColor {
         backgroundColor.setFill()
         dirtyRect.fill()
      } else {
         super.draw(dirtyRect)
      }
   }
}

// Usage
let view = View()
view.backgroundColor = .white

1

backgroundColorレイヤーに設定するだけです(ビューレイヤーをバッキングした後)。

view.wantsLayer = true
view.layer?.backgroundColor = CGColor.white

0

これにより、アプリケーションの実行中にシステム全体の外観を変更する(ダークモードをオンまたはオフにする)ことができます。ビューのクラスを最初にBackgroundColorViewに設定すると、Interface Builderで背景色を設定することもできます。


class BackgroundColorView: NSView {
    @IBInspectable var backgroundColor: NSColor? {
        didSet { needsDisplay = true }
    }

    override init(frame frameRect: NSRect) {
        super.init(frame: frameRect)
        wantsLayer = true
    }

    required init?(coder decoder: NSCoder) {
        super.init(coder: decoder)
        wantsLayer = true
    }

    override var wantsUpdateLayer: Bool { return true }

    override func updateLayer() {
        layer?.backgroundColor = backgroundColor?.cgColor
    }
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.