Transparent window in SwiftUI macOS application

Does anyone know of a way to build a macOS application in 100% SwiftUI with a transparent window background? I want to be able to place opaque SwiftUI views in front of the transparent window, so that a select portion of the window is transparent (or slightly blurred).

I know how to do this with an AppKit storyboard-based application (with embedded SwiftUI views in NSHostingController containers). However, I've not found a way to get a transparent (or slightly blurred) window within a 100% SwiftUI-based application.

Is this possible, or is the hybrid approach (AppKit storyboard + hosted SwiftUI views) the only solution?

Replies

Try something like this:

struct VisualEffect: NSViewRepresentable {
   func makeNSView(context: Self.Context) -> NSView { return NSVisualEffectView() }
}
.background(VisualEffect)

For pure transparent try something like

class TransparentWindowView: NSView {
  override func viewDidMoveToWindow() {
    window?.backgroundColor = .clear
    super.viewDidMoveToWindow()
  }
}

struct TransparentWIndow: NSViewRepresentable
   func makeNSView(context: Self.Context) -> NSView { return TransparentWindowView() }
.background(TransparentWIndow)

Repost with corrections.

Try something like this:

struct VisualEffect: NSViewRepresentable {
   func makeNSView(context: Self.Context) -> NSView { return NSVisualEffectView() }
   func updateNSView(_ nsView: NSView, context: Context) { }
}
.background(VisualEffect())

For pure transparent try something like

class TransparentWindowView: NSView {
  override func viewDidMoveToWindow() {
    window?.backgroundColor = .clear
    super.viewDidMoveToWindow()
  }
}

struct TransparentWindow: NSViewRepresentable {
   func makeNSView(context: Self.Context) -> NSView { return TransparentWindowView() }
   func updateNSView(_ nsView: NSView, context: Context) { }
}
.background(TransparentWindow())
Add a Comment

@mikeyh – how do you apply that VisualEffect to a window in a pure SwiftUI app for macOS?

@cstewart

Try something like this:

import SwiftUI

struct VisualEffect: NSViewRepresentable {
  func makeNSView(context: Self.Context) -> NSView { return NSVisualEffectView() }
  func updateNSView(_ nsView: NSView, context: Context) { }
}

@main
struct VisualEffectApp: App {
  var body: some Scene {
    WindowGroup {
      ContentView()
        .background(VisualEffect())
    }
  }
}

I tried the last solution, but the titlebar is opaque with this code:




struct VisualEffect: NSViewRepresentable {
  func makeNSView(context: Self.Context) -> NSView { return NSVisualEffectView() }
  func updateNSView(_ nsView: NSView, context: Context) { }
}

@main
struct MyApp: App {
    var body: some Scene {
        #if os(macOS)
            WindowGroup {
                ContentView()
                    .background(VisualEffect())
            }
            .windowStyle(.hiddenTitleBar)
        #endif
    }
}

Seems complicated to render the hidden title bar translucent

@Arafaer

Try something like this:

import SwiftUI

struct VisualEffect: NSViewRepresentable {
  func makeNSView(context: Self.Context) -> NSView { return NSVisualEffectView() }
  func updateNSView(_ nsView: NSView, context: Context) { }
}

@main
struct VisualEffectApp: App {
  var body: some Scene {
    WindowGroup {
      ContentView()
        .background(VisualEffect().ignoresSafeArea())
    }
    .windowStyle(.hiddenTitleBar)
  }
}

Ok thank You Mikeyh. You resolved two things in one I was .ignoresafearea() on the ContextView() so the bar was transparent but a small goofy part at the bottom, ( the size of a title bar) was background color but not translucent, weird! You resolved this. Thanks

I still have one more surely stupid question: ok the background of the window is now transparent, but only when the window has been put to front and activated(if it looses focus the background color is the system background color and no more transparent)

Thank you for your time mikeyh

  • modified post

Add a Comment

finally settled for this:

import SwiftUI

// Visual effect est la pour rendre le fond effet transparent
struct VisualEffect: NSViewRepresentable {

  func makeNSView(context: Self.Context) -> NSView {
      var test = NSVisualEffectView()
      test.state = NSVisualEffectView.State.active  // this is this state which says transparent all of the time
      return test }

  func updateNSView(_ nsView: NSView, context: Context) { }
}

better use let and not var for "test"

and Yes @mikeyh I finally read the documentation ;)

finally settled for this:

import SwiftUI

// Visual effect est la pour rendre le fond effet transparent
struct VisualEffect: NSViewRepresentable {

  func makeNSView(context: Self.Context) -> NSView {
      let test = NSVisualEffectView()
      test.state = NSVisualEffectView.State.active  // this is this state which says transparent all of the time
      return test }

  func updateNSView(_ nsView: NSView, context: Context) { }
}

  • @Arafaer & @mikeyh

    Doesn't seem to work correctly anymore in Xcode 14. When adding .background(VisualEffect().ignoresSafeArea() under ContentView and then .windowStyle(.hiddenTitleBar) to the window group, it still shows a small white title bar ( without text ) that doesn't blur. Are you guys also experiencing this issue?

  • I actually have the exact same issue, everything works except the 1px white border on top of the window

  • Okay I managed to finally do it, I used .isOpaque = false, .hasShadow = false and .toolbar = NSToolbar(). The combo of everything made it work.

Add a Comment