วิธีที่ดีที่สุดในการเปลี่ยนสีพื้นหลังสำหรับ 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

ใช่คำตอบของคุณเองถูกต้อง คุณสามารถใช้วิธีโกโก้:

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

ในสวิฟต์:

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
NSRectFillใช้NSCompositeCopyในการเติมดังนั้นมันจะปิดบังอะไรอยู่ข้างหลัง - มันจะไม่รวมอยู่ด้านบนของมุมมองบรรพบุรุษใด ๆ สำหรับการเติมด้วยสีโปร่งใสบางส่วน (หรือเต็ม -) ให้ใช้NSRectFillUsingOperation developer.apple.com/mac/library/documentation/Cocoa/Reference/…ด้วยการNSCompositeSourceOverดำเนินการ
Peter Hosey

โอ้นั่นทำให้รู้สึก ฉันลอง NSRectFill แต่ความโปร่งใสไม่ได้ผล ฉันมาที่ Cocoa จาก Cocoa Touch และแปลกใจที่เห็นว่ากรอบ Cocoa Touch นั้นสมบูรณ์กว่า (!) ฉันกำลังคิดที่จะสร้างส่วนขยายของชั้นเรียนสำหรับ NSView ที่จะช่วยให้คุณตั้งค่า backgroundColor เช่นเดียวกับ NSWindow หรือ UIView แต่ฉันไม่คิดว่าคุณจะสามารถแทนที่ drawRect ด้วยส่วนขยายได้
BadPirate

ขอโทษที่ฉันพลาดส่วนความโปร่งใส ใช่สัมผัสโกโก้ทำให้หลายสิ่งง่ายขึ้น หากคุณกำลังทำโกโก้ด้วยเช่นกันคำตอบของคุณจะดีกว่าเพราะมันพกพาได้มากกว่า
mohsenr

ฉันไม่เข้าใจนี่คือการวาดสีขาวด้านบนของมุมมองฉันเพิ่งลอง คำถามเกี่ยวกับสีพื้นหลังไม่ใช่หรือ
aneuryzm

@Patrick - คุณอาจต้องเรียก super drawRect :) หรือถ้าคุณมีสิ่งอื่นที่ควรจะวาดที่ด้านบนของพื้นหลังตรวจสอบให้แน่ใจว่าพวกเขาอยู่หลังจากการโทร NSRectFill
BadPirate

116

วิธีแก้ปัญหาที่ง่ายและมีประสิทธิภาพคือการกำหนดค่ามุมมองให้ใช้เลเยอร์ภาพเคลื่อนไหวหลักเป็นที่เก็บข้อมูลสำรอง จากนั้นคุณสามารถใช้-[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
ระวัง: โทรsetLayer:หรือsetWantsLayer:แบ่งมุมมอง WebV ใด ๆ ที่คุณอาจมีในใบสมัครของคุณด้วยวิธีที่สร้างสรรค์มาก! (แม้แต่ในหน้าต่างที่แตกต่างกัน ... )
rluba

1
setWantsLayer:มีการกำหนดใน methode : เมื่อใช้มุมมองเลเยอร์ที่ได้รับการสนับสนุนคุณไม่ควรโต้ตอบกับเลเยอร์โดยตรง คำสั่งของเวลาsetWantsLayer:และที่setLayer:เรียกว่ามีความเกี่ยวข้อง
เตฟาน

คุณไม่ควรตั้งค่าเลเยอร์ แต่ยังสามารถทำสิ่งนี้ได้ ดู ColoredView ที่objc.io/issues/14-mac/appkit-for-uikit-developers
Clafou

80

หากคุณเป็นคนรักสตอรี่บอร์ดนี่คือวิธีการที่คุณ ไม่จำเป็นต้องบรรทัดของรหัสใด

เพิ่ม NSBoxเป็นมุมมองย่อยไปที่ NSView และปรับกรอบของ NSBox เหมือนกันกับ NSView

ในกระดานเรื่องราวหรือ XIB เปลี่ยนตำแหน่งของชื่อเป็นไม่มี, ชนิดของกล่องเป็นแบบกำหนดเอง , ชนิดของเส้นขอบเป็น "ไม่มี" และสีของเส้นขอบเป็นสิ่งที่คุณต้องการ

นี่คือภาพหน้าจอ:

ป้อนคำอธิบายรูปภาพที่นี่

นี่คือผลลัพธ์ที่ได้:

ป้อนคำอธิบายรูปภาพที่นี่


การใช้ NSBox นั้นยอดเยี่ยมมากสำหรับฉัน การสลับไปใช้มุมมองแบบเลเยอร์ที่ได้รับการสนับสนุนทำให้เกิดปัญหาในการวาดใหม่
Henrik

4
นี่เป็นทางออกที่ยอดเยี่ยมและเรียบง่ายที่ควรอยู่ในเอกสาร
UKDataGeek

สีนี้ NSPopover เป็นสามเหลี่ยมไหม
Ribena

ฉันเสียใจเพียงว่าฉันมี แต่หนึ่ง upvote ที่จะให้คำตอบนี้
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 หรือสร้าง 32- บิตเช่น 64- บิต NSRect เป็นอีกวิธีหนึ่งในการพูด CGRect ถ้าไม่อย่างไรก็ตามสิ่งเหล่านี้เป็นโครงสร้างที่เป็นอิสระและแม้ว่าพวกเขาอาจประกอบด้วยสมาชิกคนเดียวกันพวกเขาไม่สามารถ "โทรฟรี - สะพาน -" เนื่องจากเป็นคำที่อ้างถึงวัตถุเท่านั้น (structs ที่มีตัวชี้ "isa" และถูกส่งผ่านโดยใช้พอยน์เตอร์) แต่ไม่ใช่โครงสร้างทั่วไป
Raphael Schweikert

การใช้ผลลัพธ์ drawRect ในเวลาวาดที่เพิ่มเป็นต้น CALayer เป็นโซลูชันที่ดีขึ้นตั้งแต่ 10.8 ขึ้นไป
Tom Andersen

22

ฉันผ่านทุกคำตอบเหล่านี้และไม่มีใครทำงานให้ฉันได้อย่างน่าเสียดาย อย่างไรก็ตามฉันพบวิธีที่ง่ายที่สุดนี้หลังจากผ่านการค้นหาประมาณหนึ่งชั่วโมง:)

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

8
โปรดทราบว่า NSViews ไม่ได้มีเลเยอร์เสมอไปซึ่งในกรณีนี้จะไม่ทำอะไรเลย ดูคำตอบของ Ioretoparisi
Kalle

3
ฉันใช้เวลามากในการพยายามทำโค้ดนี้ในวิธี viewDidLoad ของคอนโทรลเลอร์ (สำหรับ self.myCustomView) ฉันคิดว่าคุณควรใช้วิธี viewWillAppear แทน
surfrider

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

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

ฮิฮิ. มันจะใช้ได้ถ้าคุณต้องการให้มีสีพื้นหลังแบบสุ่มทุกครั้งที่คุณเปิดตัวแม้ว่าจะซับซ้อนกว่าเล็กน้อยจากนั้นก็ทำแบบเดียวกันกับการวาดรูปสี่เหลี่ยม (คำตอบที่ยอมรับ)
BadPirate

หากเป็นเพียงเรื่องของการวาดสี BG แล้วสิ่งที่จำเป็นในการเอาชนะ "drawRect:"
Nagaraj

ใช่คำตอบสูงสุดstackoverflow.com/a/2962882/285694ให้คำตอบนั้น คำถามของฉันจำเป็นต้องมีช่องอัลฟาดังนั้นฉันจึงให้เช็ค - stackoverflow.com/a/2962839/285694 - ในทางเทคนิคคำถามนี้เกี่ยวกับการตั้งค่าพื้นหลังบน NSView ด้วยช่องอัลฟ่า (เช่นเดียวกับ NSWindow) - แต่ฉันคิดว่าผู้คนมากมายมาที่นี่เพื่อค้นหาวิธีการตั้งค่าสี (คำตอบแรกจึงเป็นที่นิยมมากขึ้น)
BadPirate

6

ในสวิฟต์:

override func drawRect(dirtyRect: NSRect) {

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

    super.drawRect(dirtyRect)
}

5

ใช้ NSBox ซึ่งเป็นคลาสย่อยของ NSView ช่วยให้เรากำหนดสไตล์ได้อย่างง่ายดาย

สวิฟท์ 3

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

NSBox ไม่ได้ช่วยในกรณีของ NSPopover เนื่องจากมันยังมีส่วนสามเหลี่ยม
AnaghSharma

5

ไม่ต้องสงสัยเลยว่าวิธีที่ง่ายที่สุดเข้ากันได้กับสินทรัพย์ชุดสี:

รวดเร็ว :

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

วัตถุประสงค์ -C :

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

เครื่องมือสร้างส่วนต่อประสาน :

เพิ่มผู้ใช้แอตทริบิวต์ที่กำหนดไว้ในการสร้างอินเตอร์เฟซของประเภทbackgroundColorNSColor


สิ่งนี้ขึ้นอยู่กับพฤติกรรมที่ไม่มีเอกสารและควรหลีกเลี่ยงหากคุณยังต้องการทำงานใน AppKit เวอร์ชันอนาคต
nschmidt

3

ฉันทดสอบต่อไปนี้และใช้งานได้สำหรับฉัน (ใน Swift):

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

คุณวางรูปภาพไว้ด้านบนของมุมมองหลังจากทำสิ่งนี้หรือไม่? หรือว่าคุณใช้ NSView แทน NSImageView
justColbs

3

ใน Swift 3 คุณสามารถสร้างส่วนขยายเพื่อทำ:

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

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

1

มีลักษณะที่RMSkinnedView คุณสามารถตั้งค่าสีพื้นหลังของ NSView ได้จากภายในเครื่องมือสร้างส่วนต่อประสาน


1

ใน swift คุณสามารถ subclass 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 ก่อน


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.