3

I'm presenting a view in an NSPopover, using code based on this sample code.

The view, and all of its sub-views, are layer-backed. There's a single NSImageView, and several non-editable NSTextFields. The text fields backgroundColors are set to [NSColor textBackgroundColor], and their textColors to [NSColor textColor]. In this way, the text is black if one is using the normal theme, and white if one is using the "dark menu bar and Dock" option (which I'll refer to as "dark theme" from now on). This all works fine, and it looks a little somethin' like this:

Light theme:
light theme popover

Dark theme:
dark theme popover

The problem comes when I animate the NSImageView up off the view. As it intersects with the NSTextFields, the image appears to blend with the text fields in an unappealing manner. It happens in both light and dark themes, but it's more icky-looking (it's a technical term) in the dark theme. Dig it:

dark theme icky animation

The code to animate it looks basically like this:

CABasicAnimation* positionAnimation = [CABasicAnimation animationWithKeyPath:@"position"];
positionAnimation.fromValue = [NSValue valueWithPoint:fromPoint];
positionAnimation.toValue = [NSValue valueWithPoint:toPoint];
positionAnimation.duration = imageAnimationDuration;
[self.imageView.layer addAnimation:positionAnimation forKey:@"position"];
self.imageView.layer.position = toPoint;

What have I tried? Oh, what haven't I tried?

First off, my own views don't have any kind of NSVisualEffectView going on. But it seems that NSPopover adds that on its own; you can clearly see my desktop bleeding through the popover in the animation above. That's fine; it's actually a nice effect. But, thinking that my NSImageView was trying to be vibrant, I subclassed NSImageView just to return NO from allowsVibrancy. No change in behavior.

Next, I subclassed NSView to return NO from allowsVibrancy, and made the parent view of my view an instance of that. No change in behavior.

My NSTextFields are set with drawsBackground = NO, so I changed them to YES. No change in behavior. Then, leaving drawsBackground = YES, I set both text field's backgroundColors to [NSColor clearColor]. Here's where it gets weird. This does make the weird drawing go away, but it changes the text color of one of the text fields (the smaller one) to black. Wut? See below.

wrong text color

I gave up on the background colors, and started messing with the text colors. I found that if I set the textColor of the text fields to a discrete color (say, [NSColor blackColor] or [NSColor whiteColor], then the weird drawing problem also goes away. It seems only to get weird when using colors which adapt with the theme such as [NSColor textColor]. That's super lame, because the whole point of using something like [NSColor textColor] is that it adapts to the theme. I could probably hack around and figure out what theme is active and set the colors manually, but I really don't want to go that route if I can help it.

I promise there's a question in here somewhere, and, mercifully, here it is:

How can I fix the animation issue shown above, while still using colors which properly adapt to the current theme?

Sample project on GitHub.

Edit: The desired result is to have no blending between the image and the text. Something like this:

good-animation

The image I used in the sample app here maybe isn't the best example to convey the sheer yuckiness of the animation I'm seeing in my actual app. The image in the sample is already mostly white, while in my actual app it's mostly black, and it truly looks horrible when blended with white text.

zpasternack
  • 17,838
  • 2
  • 63
  • 81
  • 1
    I'm having a bit of trouble understanding what you want the result to actually be; the icon is going to blend with text that is the same color while also moving over the top of it. – l'L'l Aug 06 '15 at 07:33
  • @l'L'l, fair point, see my edit above. – zpasternack Aug 06 '15 at 09:16
  • The way in which `[NSTextColor textColor]` gets changed to black when using `drawsBackground = YES` seems like a bug; if it wasn't for that your method should've worked fine. Another way to see this weird behavior is to not specify an `NSColor`, but just set `self.descriptionLabel.drawsBackground = YES` then switch from dark to light, then back to dark. The behavior doesn't seem correct at all as in this example: https://gist.github.com/anonymous/14710591a913b1ee4994 – l'L'l Aug 06 '15 at 19:52

1 Answers1

1

Visual Effect Views (like used in NSPopover) are totally messed up in OS X Yosemite and they are causing your problem here. It is not your fault, these views are totally buggy.

A workaround on Yosemite should be to set the appearance property of each NSTextField to NSAppearanceNameAqua. Because if the labels don't try to do some weird vibrancy effect, they can't mess things up. The labels still look the same and the strange effect is gone.

My words in code:

self.titleLabel.appearance = [NSAppearance appearanceNamed:NSAppearanceNameAqua];
self.descriptionLabel.appearance = [NSAppearance appearanceNamed:NSAppearanceNameAqua];

Luckily NSVisualEffectView's are working fine now in El Capitan. So your code should work fine there..

mangerlahn
  • 4,746
  • 2
  • 26
  • 50