3

I'm trying to create a little Finder clone using Cocoa. I'm placing a source list table view (to act as a sidebar) and a standard table view inside of an NSSplitView controlled by an NSSplitViewController. Unfortunately, when I run this, the standard table view's white background is drawn over the bottom right corner of the window, resulting in a non-rounded corner: Bottom right corner drawn over

I'm able to avoid the problem by not using NSSplitViewController, both with standard nib files or storyboards to get the desired result:

Correctly drawn, albeit without NSSplitViewController

But… I really want to use NSSplitViewController. Is there any way to prevent this from happening?

Here is the Xcode workspace with the projects for the screenshots.

Marek H
  • 5,173
  • 3
  • 31
  • 42
Nik
  • 1,033
  • 2
  • 11
  • 28

2 Answers2

3

I have seen such problem and it seems to be real bug. But there is workaround for that. You need make sure NSSplitViewController renders itself in view which is backed by CA layer. So to do this in your project, I added man-in-the-middle view controller with container view. Then I placed your split view inside of this container view. Finally parent view of the container view is set to be layer backed. Here is the picture:

enter image description here

After that I can see everything fine:

enter image description here

On another note: make sure you dont use 1000 priority of constraints until it is really required. I normally use 750 (I fixed that as well). Otherwise you will get a lot warnings about unsatisfiable things.

Here is you fixed project: https://github.com/emankovski/splitviewroundcorrners

Eugene Mankovski
  • 1,180
  • 10
  • 16
  • How significantly does layer-backing the window content view affect performance and battery life? Presumably there must be a reason for why views are not layer backed by default? I've downloaded the fixed project and changed all of the constraint priorities to 1000 and don't seem to be getting any unsatisfiable constraint errors. I used 1000 originally because that is the default in IB, though I can see that it's not always the most appropriate. – Nik Jul 03 '16 at 12:46
  • It will actually improve you battery life. Layer backed views take advantage of GPU. In theory every view should be layer as it happens in iOS. But because CA was added to Mac afterwards, there are some recommendations to use layers prudently as they eat more memory. At the same time current macbooks have a lot of RAM so even overuse of layer backed views should not be a problem. Layers are not checked by default because they were added to Mac way later than platform was created. – Eugene Mankovski Jul 03 '16 at 12:56
1

Make sure that root view in the view hierarchy to be layer-backed BEFORE adding it to view hierarchy.

Example. This works. Tested and confirmed to work in macOS 10.12 Sierra. Xcode 8.0.

split.view.wantsLayer = true
window.contentViewController = split
split.splitViewItems = [
    NSSplitViewItem(viewController: vc),
]

But this doesn't.

window.contentViewController = split
split.splitViewItems = [
    NSSplitViewItem(viewController: vc),
]
split.view.wantsLayer = true

I don't know what's happening here, and why this works. But let me speculate.

NSWindow without layer-backing root view just draws naively with no compositor involved. So they cannot mask out corners, and such artifacts appears. Just making them layer-backed will make it work. Just as like @Eugene pointed out.

Making everything layer-backed is not hard. Just make root view to be layer-backed, and every subviews in the hierarchy will be layer-backed to the leaf. (RTFM for details: CALayer.wantsLayer.)

eonil
  • 83,476
  • 81
  • 317
  • 516