我的 NSWindow 的阴影在切换屏幕时被切断了?
My NSWindow's shadow is getting cut off when switching screens?
我想要一个背景模糊的 NSWindow,所以我在 . I also tried doing it with just the NSWindow
using https://github.com/lukakerr/NSWindowStyles#:~:text=true-,6.%20Vibrant%20background,A,-vibrant.[=17= 的帮助下为 NSVisualEffectView
创建了一个包装器,用于我的 ContentView()
]
struct VisualEffectView: NSViewRepresentable
{
let material: NSVisualEffectView.Material
let blendingMode: NSVisualEffectView.BlendingMode
func makeNSView(context: Context) -> NSVisualEffectView
{
let visualEffectView = NSVisualEffectView()
visualEffectView.material = material
visualEffectView.blendingMode = blendingMode
visualEffectView.state = NSVisualEffectView.State.active
return visualEffectView
}
func updateNSView(_ visualEffectView: NSVisualEffectView, context: Context)
{
visualEffectView.material = material
visualEffectView.blendingMode = blendingMode
}
}
它工作正常并且看起来很棒,但是,当我将 window 移动到另一个屏幕时 - 并在两个屏幕之间暂停 window,然后将其移动到下一个 window- 它砍掉了 NSWindow
阴影的一部分。
移动屏幕时是这样的⤵︎
有没有办法防止这种影子斩波的发生?
界面:SwiftUI
生命周期:Appkit AppDelegate
想通了!谢天谢地,没有任何黑客大声笑
规则
为了在没有问题中令人讨厌的伪影的情况下实现这种外观,您必须按照 macOS 要求的方式做一些事情。
1.不要设置你的 NSWindow.backgroundColor = .clear
!
这首先是造成上述令人讨厌的人工制品的原因!保持 window 的颜色不变将确保 window 在更换屏幕时正常工作。 NSVisualEffectView
捕获 window 后面的图像并将其用作背景,因此无需使任何东西透明。
2。确保在 window 的 styleMask 中包含 .titled
!
如果不这样做,将呈现没有圆角的 window。如果您尝试向 SwiftUI 视图添加圆角(就像我所做的那样),您仍然会在 NSWindow
本身上有一个不透明的背景。如果您随后将 window 的背景颜色设置为 .clear
(就像我再次做的那样),阴影切割问题就会接踵而至!但是,这并不意味着标题栏会妨碍,它不会,我们稍后会谈到。
3。将您的 NSVisualEffectView
添加到您的 SwiftUI 视图!
我发现这比将视觉效果作为子视图添加到 NSWindow.contentView
更容易。
解决方案
1.因此,请先设置您的 NSWindow
和 AppDelegate! ⤵︎
您所做的只是确保标题栏存在但隐藏。
import Cocoa
import SwiftUI
@main
class AppDelegate: NSObject, NSApplicationDelegate {
var window: NSWindow!
func applicationDidFinishLaunching(_ aNotification: Notification) {
// Create the SwiftUI view that provides the window contents.
let contentView = ContentView()
// Create the window and set the content view.
// Note: You can add any styleMasks you want, just don't remove the ones below.
window = NSWindow(
contentRect: NSRect(x: 0, y: 0, width: 300, height: 200),
styleMask: [.titled, .fullSizeContentView],
backing: .buffered, defer: false)
// Hide the titlebar
window.titlebarAppearsTransparent = true
window.titleVisibility = .hidden
// Hide all Titlebar Controls
window.standardWindowButton(.miniaturizeButton)?.isHidden = true
window.standardWindowButton(.closeButton)?.isHidden = true
window.standardWindowButton(.zoomButton)?.isHidden = true
// Set the contentView to the SwiftUI ContentView()
window.contentView = NSHostingView(rootView: contentView)
// Make sure the window is movable when grabbing it anywhere
window.isMovableByWindowBackground = true
// Saves frame position between opening / closing
window.setFrameAutosaveName("Main Window")
// Display the window
window.makeKeyAndOrderFront(nil)
window.center()
}
func applicationWillTerminate(_ aNotification: Notification) {
// Insert code here to tear down your application
}
}
此时您的 window 可能看起来像这样(如果从一个空白项目开始)。您可以看到 'Hello world!' 由于标题栏而没有完全居中。 ⤵︎
2。设置 NSWindow
后,是时候执行 ContentView()
⤵︎
在这里,您只想为 NSVisualEffectView
创建一个包装器并将其添加为背景。 然后 确保从视图中删除安全区域!这确保摆脱任何 space 标题栏在视图中的占用。
import SwiftUI
struct ContentView: View {
var body: some View {
Text("Hello, World!")
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(VisualEffectView(material: .popover, blendingMode: .behindWindow))
// Very important! (You could technically just ignore the top so you do you)
.edgesIgnoringSafeArea(.all)
}
}
/// Takes the image directly behind the window and uses that to create a blurred material. It can technically be added anywhere but most often it's used as a backing material for sidebars and full windows.
struct VisualEffectView: NSViewRepresentable {
let material: NSVisualEffectView.Material
let blendingMode: NSVisualEffectView.BlendingMode
func makeNSView(context: Context) -> NSVisualEffectView {
let visualEffectView = NSVisualEffectView()
visualEffectView.material = material
visualEffectView.blendingMode = blendingMode
visualEffectView.state = NSVisualEffectView.State.active
return visualEffectView
}
func updateNSView(_ visualEffectView: NSVisualEffectView, context: Context) {
visualEffectView.material = material
visualEffectView.blendingMode = blendingMode
}
}
此时您的视图应该看起来像您想要的那样,没有任何负面影响!享受 <3(如果您对此解决方案有任何问题,请发表评论!)
资源
感谢@eonil 以这种巧妙的方式保持圆角。没有这个答案就无法解决这个问题⤵︎
https://whosebug.com/a/27613308/13142325
感谢 lukakerr 制作这份 NSWindow 样式列表!
https://github.com/lukakerr/NSWindowStyles
我想要一个背景模糊的 NSWindow,所以我在 它工作正常并且看起来很棒,但是,当我将 window 移动到另一个屏幕时 - 并在两个屏幕之间暂停 window,然后将其移动到下一个 window- 它砍掉了 移动屏幕时是这样的⤵︎ 界面:SwiftUINSWindow
using https://github.com/lukakerr/NSWindowStyles#:~:text=true-,6.%20Vibrant%20background,A,-vibrant.[=17= 的帮助下为 NSVisualEffectView
创建了一个包装器,用于我的 ContentView()
]
struct VisualEffectView: NSViewRepresentable
{
let material: NSVisualEffectView.Material
let blendingMode: NSVisualEffectView.BlendingMode
func makeNSView(context: Context) -> NSVisualEffectView
{
let visualEffectView = NSVisualEffectView()
visualEffectView.material = material
visualEffectView.blendingMode = blendingMode
visualEffectView.state = NSVisualEffectView.State.active
return visualEffectView
}
func updateNSView(_ visualEffectView: NSVisualEffectView, context: Context)
{
visualEffectView.material = material
visualEffectView.blendingMode = blendingMode
}
}
NSWindow
阴影的一部分。有没有办法防止这种影子斩波的发生?
生命周期:Appkit AppDelegate
想通了!谢天谢地,没有任何黑客大声笑
规则
为了在没有问题中令人讨厌的伪影的情况下实现这种外观,您必须按照 macOS 要求的方式做一些事情。
1.不要设置你的 NSWindow.backgroundColor = .clear
!
这首先是造成上述令人讨厌的人工制品的原因!保持 window 的颜色不变将确保 window 在更换屏幕时正常工作。 NSVisualEffectView
捕获 window 后面的图像并将其用作背景,因此无需使任何东西透明。
2。确保在 window 的 styleMask 中包含 .titled
!
如果不这样做,将呈现没有圆角的 window。如果您尝试向 SwiftUI 视图添加圆角(就像我所做的那样),您仍然会在 NSWindow
本身上有一个不透明的背景。如果您随后将 window 的背景颜色设置为 .clear
(就像我再次做的那样),阴影切割问题就会接踵而至!但是,这并不意味着标题栏会妨碍,它不会,我们稍后会谈到。
3。将您的 NSVisualEffectView
添加到您的 SwiftUI 视图!
我发现这比将视觉效果作为子视图添加到 NSWindow.contentView
更容易。
解决方案
1.因此,请先设置您的 NSWindow
和 AppDelegate! ⤵︎
您所做的只是确保标题栏存在但隐藏。
import Cocoa
import SwiftUI
@main
class AppDelegate: NSObject, NSApplicationDelegate {
var window: NSWindow!
func applicationDidFinishLaunching(_ aNotification: Notification) {
// Create the SwiftUI view that provides the window contents.
let contentView = ContentView()
// Create the window and set the content view.
// Note: You can add any styleMasks you want, just don't remove the ones below.
window = NSWindow(
contentRect: NSRect(x: 0, y: 0, width: 300, height: 200),
styleMask: [.titled, .fullSizeContentView],
backing: .buffered, defer: false)
// Hide the titlebar
window.titlebarAppearsTransparent = true
window.titleVisibility = .hidden
// Hide all Titlebar Controls
window.standardWindowButton(.miniaturizeButton)?.isHidden = true
window.standardWindowButton(.closeButton)?.isHidden = true
window.standardWindowButton(.zoomButton)?.isHidden = true
// Set the contentView to the SwiftUI ContentView()
window.contentView = NSHostingView(rootView: contentView)
// Make sure the window is movable when grabbing it anywhere
window.isMovableByWindowBackground = true
// Saves frame position between opening / closing
window.setFrameAutosaveName("Main Window")
// Display the window
window.makeKeyAndOrderFront(nil)
window.center()
}
func applicationWillTerminate(_ aNotification: Notification) {
// Insert code here to tear down your application
}
}
此时您的 window 可能看起来像这样(如果从一个空白项目开始)。您可以看到 'Hello world!' 由于标题栏而没有完全居中。 ⤵︎
2。设置 NSWindow
后,是时候执行 ContentView()
⤵︎
在这里,您只想为 NSVisualEffectView
创建一个包装器并将其添加为背景。 然后 确保从视图中删除安全区域!这确保摆脱任何 space 标题栏在视图中的占用。
import SwiftUI
struct ContentView: View {
var body: some View {
Text("Hello, World!")
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(VisualEffectView(material: .popover, blendingMode: .behindWindow))
// Very important! (You could technically just ignore the top so you do you)
.edgesIgnoringSafeArea(.all)
}
}
/// Takes the image directly behind the window and uses that to create a blurred material. It can technically be added anywhere but most often it's used as a backing material for sidebars and full windows.
struct VisualEffectView: NSViewRepresentable {
let material: NSVisualEffectView.Material
let blendingMode: NSVisualEffectView.BlendingMode
func makeNSView(context: Context) -> NSVisualEffectView {
let visualEffectView = NSVisualEffectView()
visualEffectView.material = material
visualEffectView.blendingMode = blendingMode
visualEffectView.state = NSVisualEffectView.State.active
return visualEffectView
}
func updateNSView(_ visualEffectView: NSVisualEffectView, context: Context) {
visualEffectView.material = material
visualEffectView.blendingMode = blendingMode
}
}
此时您的视图应该看起来像您想要的那样,没有任何负面影响!享受 <3(如果您对此解决方案有任何问题,请发表评论!)
资源
感谢@eonil 以这种巧妙的方式保持圆角。没有这个答案就无法解决这个问题⤵︎
https://whosebug.com/a/27613308/13142325
感谢 lukakerr 制作这份 NSWindow 样式列表! https://github.com/lukakerr/NSWindowStyles