6

How display a NSVisualEffectView with with rounded corners in OS X?

My code to add my NSVisualEffectView:

let visualEffectView = NSVisualEffectView(frame: NSMakeRect(0, 0, 300, 300))
visualEffectView.material = NSVisualEffectMaterial.Dark
visualEffectView.blendingMode = NSVisualEffectBlendingMode.BehindWindow
self.addSubview(visualEffectView)
Geek20
  • 673
  • 1
  • 9
  • 18
  • Try [maskImage](https://developer.apple.com/library/mac/documentation/Foundation/Reference/NSVisualEffectView_Class/#//apple_ref/occ/instp/NSVisualEffectView/maskImage). – jtbandes Aug 17 '15 at 03:34
  • Do you have an example? I tried but i can't – Geek20 Aug 17 '15 at 05:04

3 Answers3

10

You can enable layer backed views for your NSVisualEffectView by setting wantsLayer to true and then set the cornerRadius of the backing layer:

    let visualEffectView = NSVisualEffectView(frame: NSMakeRect(0, 0, 300, 300))
    visualEffectView.material = NSVisualEffectMaterial.Dark
    visualEffectView.blendingMode = NSVisualEffectBlendingMode.BehindWindow
    visualEffectView.wantsLayer = true
    visualEffectView.layer?.cornerRadius = 15.0
    self.view.addSubview(visualEffectView)

This results in a effect view with nice rounded corners:

enter image description here

Thomas Zoechling
  • 34,177
  • 3
  • 81
  • 112
  • 3
    Thanks it works! however i have a problem because i want my visualEffectView (**Dark**) above other visualEffectView0 (with material: **Match Appearance**) and the cornerRadius doesn't work, do you know how to fix it? --> [screenshot](http://d.pr/i/115rY) – Geek20 Aug 17 '15 at 07:34
  • Don't know yet how to fix it, but [here is an issue](https://github.com/twostraws/VisualEffects/issues/3), maybe someone will help – maximkrouk Jun 28 '20 at 12:19
  • This didn't work for me - it insisted on drawing the 'outside' of the corners in black. – Confused Vorlon Nov 17 '20 at 15:50
2

NSVisualEffectView has a maskImage property which you can use to clip the view to an arbitrary shape.

From the header:

/* The mask image masks this view. It is best to set this to the
   smallest mask image possible and properly set the image.capInsets to
   inform the image on how to stretch the contents when it is used as a
   mask. Setting the maskImage on an NSVisualEffectView that is the
   window.contentView will correctly set the window's shadow.
 */
public var maskImage: NSImage?

For example, you can use an NSImage with rounded corners and set its capInsets to the corner radius and its resizingMode to .stretch.

sam
  • 3,399
  • 4
  • 36
  • 51
1

Swift 5.5

For one of my apps I was doing exactly what @sam said. And here is the result:

enter image description here

What you need to do:

  • define an extension on NSImage:
extension NSImage {
    static func mask(withCornerRadius radius: CGFloat) -> NSImage {
        let image = NSImage(size: NSSize(width: radius * 2, height: radius * 2), flipped: false) {
            NSBezierPath(roundedRect: $0, xRadius: radius, yRadius: radius).fill()
            NSColor.black.set()
            return true
        }
        
        image.capInsets = NSEdgeInsets(top: radius, left: radius, bottom: radius, right: radius)
        image.resizingMode = .stretch
        
        return image
    }
}
  • create visual effect view
private lazy var visualEffectView: NSVisualEffectView = {
    let visualEffectView = NSVisualEffectView()
    visualEffectView.blendingMode = .behindWindow
    visualEffectView.material = .popover
    visualEffectView.state = .active
    visualEffectView.maskImage = .mask(withCornerRadius: 25)
    return visualEffectView
}()

Happy coding ;)

Sapozhnik Ivan
  • 235
  • 3
  • 7