NSViews, unless UIViews, are not always backed by Core Animation layers. In fact, by default, they don’t have anything to do with CALayers. You can optionally choose to make an NSView a layer-backed view, a layer-hosting view, or have nothing to do with them.

Other than that, CoreAnimation on OSX is the same as CoreAnimation on iOS. You don’t even need to flip your coordinate system (as CoreAnimation on iOS uses bottom-left as the origin - which OSX uses by default).

Note that actually using Core Animation will be a future, more generic, article, this is just how to set it up with AppKit.

Layer-Backed

A layer-backed view means that the view delegates all the drawing to a CALayer that it manages. Setting one view to be layer-backed automatically sets all of it’s subviews (and onwards) to be layer-backed. Additionally, if you want to directly do stuff to the layer, you need to set the wantsUpdateLayer property to true. UIViews behave like this by default.

Layer-Backed views are always more performant than views w/o layers. But, in general, you don’t need to make all views layer-backed, only if you’re feeling pain on that.

To set a view as layer-backed, you need to set the wantsLayer property to true, and not set the layer property.

In code:

let view = NSView()
view.wantsLayer = true // makes it layer-backed
view.wantsUpdateLayer = true // allows you to safely directly access the layer
assert(view.layer != nil, "this should always pass")
view.layer?.cornerRadius = 5

Layer-Hosting

The difference between a layer-backed view and a layer-hosting view is that the system manages the layer in a layer-backed view, whereas you must manage the layer for a layer-hosting view.

To create a layer-hosting view, set the layer property to a CALayer, then set the wantsLayer to true. In that order.

You would want to use the Layer-Hosting technique when you just want one view in a hierarchy to have a layer, but not all of them.

In code:

let view = NSView(frame: CGRectMake(0, 0, 10, 10)
let layer = CALayer()
view.layer = layer
view.wantsLayer = true

layer.bounds = view.bounds
layer.cornerRadius = 5

Reference

  1. Programmatic Menu Buttons
  2. Programmatically creating a scrolling TableView