5

I'm building a NSView hierarchy programmatically by putting a NSStackView into a NSScroller. I have done this before and my code is correct.

The view hierarchy is what I expect until the first time through the runloop (or display) where macOS Catalina (and I think Mojave) automatically insert a NSVisualEffectView into the view hierarchy. This is messing up my custom drawing no end..

The hierarchy that I create is

NSScrollView -> NSStackView -> stack subviews

this is "enriched" by the scroll view before the first display loop into:

NSScrollView -> NSClipView -> NSStackView -> stack subviews

and after the first display the NSVisualEffects View is added at the same level as the NSClipView:

NSScrollView -> NSClipView          -> NSStackView -> stack subviews
             -> NSVisualEffectsView

Is there a way to tell the scroll view that I don't want the visual effects view?

Any help would be appreciated!

Frank R.
  • 2,328
  • 1
  • 24
  • 44
  • This is similar to the [problem with NSPredicateEditor in a sheet](https://stackoverflow.com/questions/53345734/macos-dark-mode-ui-bugs-with-nspredicateeditor-in-a-sheet/60842764), but in that case Apple is *not* inserting the VEV and everything looks wrong as a result. My code there for adding it might be useful for removing it. – pkamb Mar 26 '20 at 18:09

3 Answers3

3

I'm facing the same issue when I try to recreate the spotlight window. The screenshot below shows a table view (enclosed in a scroll view) in a visual effect view:

enter image description here

In older version of macOS, the opaque background here is the background drawn on scroll view (or clip view), which we can simply remove it by setting a clear background color, or setting drawBackground to false as Lucas suggested.

However, due to the insertion of this visual effect view in newer version of macOS (Catalina, maybe?), this won't works:

enter image description here

It has an opaque content background material, and I don't find any APIs or documents related to this behavior.


The Workaround

What works for me is to hide the inserted visual effect view in my NSScrollView subclass:

class ScrollView: NSScrollView {
    override func didAddSubview(_ subview: NSView) {
        super.didAddSubview(subview)

        if subview is NSVisualEffectView {
            subview.isHidden = true
        }
    }
}

enter image description here


Update

If you are using NSTableView, instead of the above "hack", it's preferred to set table view's style to be source list:

// for macOS 11 Big Sur
tableView.style = .sourceList

// for macOS 10.15 Catalina and older
tableView.selectionHighlightStyle = .sourceList

When you do so, the system automatically configure the scroll view and table view for source list appearance (or sidebar). More specifically, scroll view doesn't insert visual effect view, and the table view's row view are semi-transparent.

ix4n33
  • 526
  • 4
  • 10
1

Pretty sure you have to set drawsBackground to be false. So with a reference to NSScrollView, you'd call something like this after the view is loaded up or assign this value in the xib/storyboard file.

scrollView.drawsBackground = false
Lucas Derraugh
  • 6,929
  • 3
  • 27
  • 43
1

When you add an NSTableView or NSCollectionView inside an NSScrollView its drawsBackground property is ignored and an NSVisualEffects view added unless you explicitly set .backgroundColor = .clear on table view and collectionview inside.

So for correct behavior:

tableView.backgroundColor = .clear
scrollView.drawsBackground = false
Umur Gedik
  • 477
  • 5
  • 12