6

I want to use NSVisualEffectView with dark vibrancy, but I find the effect too pale in some situations, so I'd like to darken the background.

Here is an example app, using NSBox views to provide a darker background.

enter image description here

We can see that the NSBox 'primary' appearance manages to overlay the background and the button happily sits on top of that. However, on the NSBox with custom appearance, the button appears to 'cut' through the background to the visual effect view beneath.

I've tried subclassing NSVisualEffectView and overriding -drawRect: to fill it with a different color and the result is the same.

Is there a way to overlay vibrant controls over other views?

Andriy
  • 2,767
  • 2
  • 21
  • 29
joerick
  • 16,078
  • 4
  • 53
  • 57

1 Answers1

1

The Visual Effect View seems to have two important layers: Backdrop and Tint. Setting both of these to the "right" black seems to do the trick, but you'll need to do this anytime the bounds change.

for (CALayer *sublayer in self.vibrancyView.layer.sublayers) {
    if ([sublayer.name isEqualToString:@"Backdrop"]) {
        NSLog(@"Backdrop: %@", sublayer.backgroundColor);
        sublayer.backgroundColor = [NSColor colorWithRed:0 green:0 blue:0 alpha:0.45].CGColor;
    } else if ([sublayer.name isEqualToString:@"Tint"]) {
        NSLog(@"Tint: %@", sublayer.backgroundColor);
        sublayer.backgroundColor = [NSColor colorWithRed:0 green:0 blue:0 alpha:1].CGColor;
    }
}
joerick
  • 16,078
  • 4
  • 53
  • 57
Dimitri Bouniol
  • 735
  • 11
  • 15
  • I can't get this to work. Are you doing within-window blending or behind-window blending? – joerick Nov 18 '14 at 12:02
  • Within-window. Using the same technique, are you able to log the sublayers of an empty visual effect view to see what's available to play with? – Dimitri Bouniol Nov 18 '14 at 16:11
  • Ah. I need behind-window blending. But I did try logging the layers in `setFrame:` and `setBounds:` on the NSView, there was nothing there. I guess they were set up after the layout pass. – joerick Nov 18 '14 at 17:20
  • Apparently behind window blur is done by the window server, so maybe you have no control over that. Maybe adding a black layer with a plusL/plusD compositing filter (log the Tint layer's compositing filter from a within window view for an example) to the visual effect view might work? – Dimitri Bouniol Nov 18 '14 at 22:55
  • Checking the compositing filter on an allows vibrancy view gives the following, which leads me to think you can just say `layer.compositingFilter = @"plusL"`; `(lldb) po commandView.layer > (lldb) po commandView.layer.compositingFilter plusL (lldb) po [commandView.layer.compositingFilter class] __NSCFConstantString` – Dimitri Bouniol Nov 18 '14 at 23:00