Sake
Sake

Reputation: 645

Reproduce the exact background effect of macOS control center items in the status bar

I am trying to reproduce the background blur/color effect that is used by macOS Control Center items such as Wifi, Sound, Battery, etc, that can be found in the status bar.

Normally to achieve this background effect you would use a NSVisualEffectView

let view = NSVisualEffectView()
view.blendingMode = .behindWindow
view.state = .active
view.material = .popover //

However, none of the material options match exactly to the effect visible in the Apple control center items. In fact app menus that are on the left part of the status bar do have the same blur/color as the .popover material, so they actually do do something different.

Almost all status bar apps that have source files online do also use the .popover effect to mimic the effect, but it isn't exactly equal. Also using MenuBarExtra with menuBarExtraStyle(.window) does not result in the same background. Also the material backgrounds in SwiftUI do not produce the same effect.

Below I have provided two screenshots, the left part showing the NSPanel that tries to mimic the color/background effect of a Control Center item. As can be seen, they appear very similar but do have a slight difference in color.

So far I have tried to use white overlays with a low opacity, all of the materials available, blendingModes of overlays in SwiftUI, but so far had no luck.

So my question, how can I reproduce the same background effect as the Control Center items in macOS?

enter image description here

class DemoPanel: NSPanel {
    lazy var visualEffectView: NSVisualEffectView = {
        let view = NSVisualEffectView()
        view.blendingMode = .behindWindow
        view.state = .active
        view.material = .popover
        
        return view
    }()
    
    init() {
        super.init(
            contentRect: CGRect(x: 0, y: 0, width: 300, height: 100),
            styleMask: [.borderless, .fullSizeContentView, .nonactivatingPanel, .utilityWindow],
            backing: .buffered,
            defer: false
        )
        
        collectionBehavior = [.canJoinAllApplications]
        
        isMovable = false
        isMovableByWindowBackground = false
        isFloatingPanel = true
        level = .statusBar
        isOpaque = false
        titleVisibility = .hidden
        titlebarAppearsTransparent = true
        titlebarSeparatorStyle = .none
        
        isReleasedWhenClosed = false
        hidesOnDeactivate = false
        
        standardWindowButton(.closeButton)?.isHidden = true
        standardWindowButton(.miniaturizeButton)?.isHidden = true
        standardWindowButton(.zoomButton)?.isHidden = true
        
        contentView = visualEffectView
    }
}

Upvotes: 2

Views: 159

Answers (0)

Related Questions