14

I am creating an app where I need to have a transparent NSView with a transparent PNG image inside. The problem is, the NSView I'm drawing has a gray background on it. I have it subclassed (as TransparentRectangleView) but don't know what to put in drawRect to make it transparent.

I have already overridden the isOpaque method to return NO but it doesn't seem to help...

Alternatively, is there already a subclassed NSView that is similar to the iPhone's UIImageView (as long as I can add subviews inside, I need to add some text inside).

Andrew M
  • 4,208
  • 11
  • 42
  • 67
  • 1
    Isn't there a transparency slider in Interface Builder? I seem to remember accidentally turning down the opacity of one of my views. – Sam Dufel Jan 08 '11 at 18:30
  • 1
    I'm almost 100% sure that sets the transparency of the entire view, including the children. That would mean all of my buttons and text would also have 1% opacity or whatever. If I am wrong, please let me know :D – Andrew M Jan 08 '11 at 18:34
  • 1
    Wait, so you just want a transparent background color? I know for UIViews there's a predefined transparent color you can use, although I haven't tried using it with NSViews. – Sam Dufel Jan 08 '11 at 18:40
  • Yeah, I'm on the Mac though so the UIView isn't the same as NSView. Anyways, solved the problem with FakeImageView – Andrew M Jan 08 '11 at 18:45
  • @Andrew M, you're wrong, a view's transparency does not affect its children. Views are drawn independently of one another. – d11wtq Jan 09 '11 at 02:21

3 Answers3

20

To make a view transparent, simply fill it with [NSColor clearColor].

- (void)drawRect:(NSRect)rect {
    [[NSColor clearColor] set];
    NSRectFill(rect);
}

The default implementation of isOpaque returns NO, so if you are subclassing NSView and not some other view you don't need to worry about overriding it.

ughoavgfhw
  • 39,734
  • 6
  • 101
  • 123
  • This is very useful for the future! Thanks! – Andrew M Jan 08 '11 at 21:45
  • 4
    Incidentally, I'm reasonably sure if you leave `drawRect:` empty you get the same effect, since you'll be drawing nothing. Reasonable sure = certain, since I do this frequently. – d11wtq Jan 09 '11 at 02:22
  • Your code draws a black rectangle unless you set the window to be non-opaque (the window, not the view! NSView's are non-opaque by default but NSWindow's are opaque by default). See also this text http://www.drissman.com/blog/archives/2009/10/09/nsrectfill_and_nscolor_clearcolor.html So you either want to mention that about the window or use NSRectFillUsingOperation as shown in the text. Oh, it will also work if your view is layered as in that case it has an own drawing layer. – Mecki Dec 08 '16 at 14:22
  • @Mecki The OP does not seem to be asking about making the entire window transparent. Just the view so you can see other views under it. – ughoavgfhw Dec 09 '16 at 01:12
  • @ughoavgfhw You don't seem to understand: Your code draws black, unless the window is set to non-opaque. It doesn't matter if the OP wants a non-opaque window or not, your code only works on a non-opaque window. Have you ever tried your code for real? – Mecki Dec 09 '16 at 11:30
  • Copy that code http://rextester.com/SHLGC62567 to `main.m`, compile with `clang -framework Cocoa -o windowtest main.m` and run with `./windowtest`. Here's what the output looks like: https://s29.postimg.org/6a4mv566f/so_4635442.png Does the window top left looks like it has a transparent NSView? Nope. But that's exactly what your code does on a non-opaque window, unless the content view is layered (which it isn't by default) – Mecki Dec 09 '16 at 13:10
11

The accepted answer does not work for me since mine window is opaque. As http://www.drissman.com/blog/archives/2009/10/09/nsrectfill_and_nscolor_clearcolor.html (and the discussion below) said, the following codes work:

- (void)drawRect:(NSRect)rect {
    [[NSColor clearColor] set];
    NSRectFillUsingOperation(rect, NSCompositeSourceOver);
    // do other drawings
}
lk_vc
  • 1,136
  • 20
  • 26
  • 1
    SourceOver is, for most things, the default compositing operation. This is no different from `[NSBezierPath fillRect:]` and both less efficient and less effective than `NSRectFill`, which (unusually) uses `NSCopyCompositeOperation`. And, as d11wtq says on the accepted answer, this isn't necessary anyway—the view itself is already transparent except where you draw otherwise. – Peter Hosey Apr 23 '13 at 01:26
  • @PeterHosey Did you even read what the text at the link says? No, it's not the same. NSRectFill with a transparent color will only work if the window has not been explicitly set not-opaque, what you can do, of course, but it wastes a lot of computation time if your window in fact is opaque. NSRectFillUsingOperation will work correctly, if the window is opaque or not. The text at the link explains this very nicely and just saved me tons of work. – Mecki Dec 08 '16 at 14:16
7

The Swift version:

override func draw(_ dirtyRect: NSRect) {

    NSColor.clear.set()
    dirtyRect.fill()
}
sebastienhamel
  • 313
  • 2
  • 10