NSView için arka plan rengini değiştirmenin en iyi yolu


153

Ben değiştirmenin en iyi yolu arıyorum backgroundColorbir bir NSView. Ayrıca için uygun alphamaskeyi ayarlamak istiyorum NSView. Gibi bir şey:

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

Bunun NSWindowbu yönteme sahip olduğunu fark ettim ve NSColorWheelveya NSImagearka plan seçeneklerinin büyük bir hayranı değilim , ancak en iyisiyse, kullanmaya istekliyim.

Yanıtlar:


135

Evet, cevabın doğruydu. Kakao yöntemlerini de kullanabilirsiniz:

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

Swift'de:

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
NSRectFillNSCompositeCopydolguyu yapmak için kullanır , böylece arkasındaki her şeyi bozar — herhangi bir ata görünümünün üzerine birleşmez. Kısmen (veya tamamen) şeffaf renkli dolgular için, işlemle birlikte NSRectFillUsingOperation developer.apple.com/mac/library/documentation/Cocoa/Reference/… kullanın NSCompositeSourceOver.
Peter Hosey

Oh, bu mantıklı. NSRectFill'i denedim ama şeffaflık işe yaramadı. Cocoa Touch'tan Cocoa'ya geliyorum ve Cocoa Touch çerçevesinin bazı açılardan daha eksiksiz (!) Olduğunu görünce şaşırıyorum. NSView için, bir NSWindow veya UIView gibi backgroundColor ayarlamanıza izin verecek bir sınıf uzantısı yapmayı düşünüyordum, ancak drawRect'i bir uzantıyla geçersiz kılabileceğinizi sanmıyorum.
BadPirate

Üzgünüm şeffaflık kısmını kaçırdım. Evet, Cocoa touch birçok şeyi kolaylaştırır. Kakao dokunuşu da yapıyorsanız, daha taşınabilir olduğu için kendi cevabınız aslında daha iyidir.
mohsenr

Anlamıyorum, bu görüntünün üstüne beyaz rengi çiziyor, daha yeni denedim. Arka plan rengi ile ilgili soru değil miydi?
aneuryzm

@Patrick - super drawRect'i aramanız gerekebilir :) veya arka planın üzerine çizilmesi gereken başka şeyleriniz varsa, bunların NSRectFill çağrısından sonra olduklarından emin olun.
BadPirate

116

Görünümü, destek deposu olarak bir Temel Animasyon katmanını kullanacak şekilde yapılandırmak kolay ve verimli bir çözümdür. Daha sonra -[CALayer setBackgroundColor:]katmanın arka plan rengini ayarlamak için kullanabilirsiniz .

- (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;
}

Bu kadar!


6
Dikkat: uygulamanızda sahip olabileceğiniz Web Görünümlerini çok yaratıcı yollarla çağırır setLayer:veya setWantsLayer:bozar! (Farklı pencerelerde bile ...)
rluba

1
Yöntemde setWantsLayer:tanımlanmıştır: Katman destekli görünümleri kullanırken katmanla asla doğrudan etkileşime girmemelisiniz . Ne zaman setWantsLayer:ve ne zaman setLayer:çağrıldığının sırası önemlidir.
Stephan

Katmanı ayarlamamalısınız ama yine de bunu başarabilirsiniz. En ColoredView bakın objc.io/issues/14-mac/appkit-for-uikit-developers
Clafou

84

Bir storyboard aşığıysanız, işte herhangi bir kod satırına ihtiyacınız olmayan bir yol .

Ekle NSBoxNSView bir subview ve NSView ile aynı olarak NSBox en çerçevesini ayarlamak.

Storyboard veya XIB'de Başlık konumunu Yok olarak, Kutu türünü Özel olarak , Kenarlık Tipini "Yok" olarak ve Kenarlık rengini istediğiniz şekilde değiştirin.

İşte bir ekran görüntüsü:

görüntü açıklamasını buraya girin

Sonuç şu:

görüntü açıklamasını buraya girin


NSBox'ı kullanmak benim için harika çalıştı. Katman destekli görünüme geçiş, yeniden çizim sorunlarına neden olurken kutu buna neden olmadı.
Henrik

4
Bu, dokümanlarda olması gereken mükemmel ve basit bir çözüm
UKDataGeek

Bu renk NSPopover üçgenler mi?
Ribena

Sadece bu cevabı vermek için bir oy hakkım olduğu için üzgünüm.
orion elenzil

34

Önce WantsLayer öğesini YES olarak ayarlarsanız, katman arka planını doğrudan değiştirebilirsiniz.

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

26

Sanırım bunu nasıl yapacağımı anladım:

- (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));
}

Teşekkürler. DirtyRect'i bir CGRect'e dönüştürmem gerekiyordu. Son satır CGContextFillRect(context, NSRectToCGRect(dirtyRect));değiştirildi Cevabınızı düzenleyebilir misiniz?
Ross

1
Eskiden ücretsiz köprülerdi: /
BadPirate

6
64-bit veya iOS için derleme yaparken veya 64-bit gibi 32-bit oluştururken NSRect, CGRect demenin başka bir yoludur. Değilse, bunlar bağımsız yapılardır ve aynı üyelerden oluşsalar bile, yalnızca nesnelere ("isa" işaretçisine sahip yapılar) atıfta bulunan bir terim olduğundan, hiçbir zaman "ücretsiz köprülü" olamazlar. ve işaretçiler kullanılarak çevrilir, ancak genel yapılara aktarılmaz.
Raphael Schweikert

drawRect kullanımı ek çekme süresi vb. ile sonuçlanır. CALayer, 10.8 ve üstü sürümlerde daha iyi bir çözümdür.
Tom Andersen

22

Tüm bu cevapların üzerinden geçtim ve ne yazık ki hiçbiri benim için işe yaramadı. Ancak, yaklaşık bir saatlik aramadan sonra bunu son derece basit buldum :)

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

8
NSViews her zaman bir katmana sahip değildir, bu durumda bu hiçbir şey yapmaz. Ioretoparisi'nin cevabına bakın.
Kalle

3
Bu kodu denetleyicimin viewDidLoad yönteminde (self.myCustomView için) gerçekleştirmeye çalışırken çok zaman harcadım. Bunun yerine viewWillAppear yöntemini kullanmanız gerektiğini anladım.
sörfçü

21

düzenle / güncelle: 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
        }
    }
}

kullanım:

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)

Bunun en temiz çözüm olduğunu düşünüyorum, ancak Objc.io halkının burada yaptığı açıklamadan endişe duyuyorum: objc.io/issues/14-mac/appkit-for-uikit-developers - "... etkileşim kurmaya çalışmamalısınız AppKit bu katmanlara sahip olduğu için doğrudan katmanlarla. " Neyin ters gidebileceğinden emin değilim. Her iki durumda da, bu çözümü kendi kodumda kullanıyorum.
Kevin Sliech

7

En İyi Çözüm:

- (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);
    }
}

Hehe. Her başlattığınızda rastgele bir arka plan rengine sahip olmak isterseniz işe yarar, ancak biraz daha karmaşık ve sonra aynı şeyi draw rect (kabul edilen cevap) ile yapın
BadPirate

Eğer mesele sadece bir BG rengi çizmekle ilgiliyse, o zaman "drawRect:" i geçersiz kılmak için ne gerekli?
Nagaraj

Evet, en iyi yanıt stackoverflow.com/a/2962882/285694 bu yanıtı verir. Sorum aslında bir alfa kanalına sahip olmayı gerektirdi, bu yüzden buna bir onay verdim - stackoverflow.com/a/2962839/285694 - Teknik olarak bu soru, bir Alfa kanalı ile bir NSView'da arka planı ayarlamakla ilgilidir (NSWindow ile yapabileceğiniz gibi) - Ama bence pek çok insan buraya rengi nasıl ayarlayacağını araştırmaya geliyor (bu nedenle ilk cevap daha popüler).
BadPirate

6

Swift'de:

override func drawRect(dirtyRect: NSRect) {

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

    super.drawRect(dirtyRect)
}

5

NSView'ın bir alt sınıfı olan NSBox'ı kullanın ve kolayca biçimlendirmemizi sağlar.

Hızlı 3

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

Üçgen kısma sahip olduğu için NSBox, NSPopover durumunda yardımcı olmaz.
AnaghSharma

5

Kuşkusuz en kolay yol, Renk Seti Varlıkları ile de uyumludur:

Swift :

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

Amaç-C :

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

Arayüz Oluşturucu :

backgroundColorArayüz oluşturucuya türünde bir kullanıcı tanımlı öznitelik ekleyin NSColor.


Bu, belgelenmemiş davranışa dayanır ve hala AppKit'in gelecekteki sürümlerinde çalışmak istiyorsanız bundan kaçınılmalıdır.
nschmidt

3

Aşağıdakileri test ettim ve benim için çalıştı (Swift'de):

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

Bunu yaptıktan sonra görüntünün üstüne bir resim mi koydun? Veya NSImageView yerine NSView kullandınız mı?
justColbs

3

Swift 3'te, bunu yapmak için bir uzantı oluşturabilirsiniz:

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

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


1

Hızlı bir şekilde NSView'ı alt sınıflayabilir ve bunu yapabilirsiniz

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

Sadece küçük yeniden kullanılabilir sınıf (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

Bu, uygulama çalışırken sistem genelindeki görünümün değiştirilmesini (karanlık modu açma veya kapatma) destekler. Önce görünüm sınıfını BackgroundColorView olarak ayarlarsanız, Arayüz Oluşturucu'da arka plan rengini de ayarlayabilirsiniz.


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
    }
}

1

Sadece backgroundColorkatmanı ayarlayın (görünüm katmanını yedekledikten sonra).

view.wantsLayer = true
view.layer?.backgroundColor = CGColor.white
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.