Base on macOS 10.15, Xcode 11.7.
异常描述
1、当程序运行在非活跃状态时,且 NSWindow 为默认样式(可关闭、缩放、有标题栏等)。
此时如果点击 NSWindow 中的按钮,一般情况下会将该 NSWindow 变成活跃状态,同时触发按钮的 action 一次。但对于 PlainButtonStyle 样式的按钮,却无法触发其事件函数!
2、当程序运行在非活跃状态时,且 NSWindow 为空样式(styleMask = []),且允许拖动(isMovableByWindowBackground = true)。
此时如果点击 NSWindow 中的按钮,一般情况下会将该 NSWindow 变成活跃状态,同时触发按钮的 action 一次。但对于 PlainButtonStyle 样式的按钮,却会触发其事件函数两次!
测试代码
import SwiftUI struct ContentView: View { var body: some View { VStack { Button("Normal") { NSLog("normal Button clicked") } Button(action: { NSLog("LinkButton clicked") }){ Text("LinkButton") }.buttonStyle(LinkButtonStyle()) Button(action: { NSLog("BorderedButton clicked") }){ Text("BorderedButton") }.buttonStyle(BorderedButtonStyle()) Button(action: { NSLog("BorderlessButton clicked") }){ Text("BorderlessButton") }.buttonStyle(BorderlessButtonStyle()) Button(action: { NSLog("PlainButton clicked") }){ Text("PlainButton") }.buttonStyle(PlainButtonStyle()) }.frame(width: 400, height: 300) } }
import Cocoa import SwiftUI @NSApplicationMain class AppDelegate: NSObject, NSApplicationDelegate { var window: NSWindow! func applicationDidFinishLaunching(_ aNotification: Notification) { // Create the SwiftUI view that provides the window contents. let contentView = ContentView() // 👇 When App runs in backend, PlainButtonStyle Button could be triggered window = NSWindow( contentRect: NSRect(x: 0, y: 0, width: 480, height: 300), styleMask: [.titled, .closable, .miniaturizable, .resizable, .fullSizeContentView], backing: .buffered, defer: false) // 👇 When App runs in backend, PlainButtonStyle Button trigger twice // window = NSWindow( // contentRect: NSRect(x: 0, y: 0, width: 480, height: 300), // styleMask: [], // backing: .buffered, defer: false) // window.isMovableByWindowBackground = true window.center() window.setFrameAutosaveName("Main Window") window.contentView = NSHostingView(rootView: contentView) window.makeKeyAndOrderFront(nil) } func applicationWillTerminate(_ aNotification: Notification) { // Insert code here to tear down your application } }
解决办法
我把项目中的所有 PlainButtonStyle 按钮全部改成 BorderlessButtonStyle 了。