如何在 SwiftUI 中以降低透明度为菜单项获取 AccentColor 背景?

Posted

技术标签:

【中文标题】如何在 SwiftUI 中以降低透明度为菜单项获取 AccentColor 背景?【英文标题】:How to get accentColor background for menu items in SwiftUI with reduced transparency? 【发布时间】:2020-01-21 09:33:15 【问题描述】:

使用 AppKit,您可以将 NSMenuItems 添加到 NSMenu。我看到SwiftUI中有一个类似于NSMenu的东西,即MenuButton。但我找不到任何关于它如何工作的文档。

我尝试了以下方法:

MenuButton("+") 
    Button("New contact")  print("Create new contact") 
    Button("New group")  print("Create new group") 

这给了我这个

看起来几乎没问题但是当我在系统偏好设置中启用“降低透明度”时

按钮的背景颜色与菜单不同(请注意菜单项上方和下方的颜色稍浅)。 当我悬停菜单项时,它们的背景颜色不会像正常的 macOS 菜单那样改变。见下图:

我还尝试使用 .background() 修饰符手动更改背景颜色,但这不会影响菜单项的整个宽度。

MenuButton("+") 
    Button("New contact")  print("Create new contact") 
        .background(Color.accentColor)
    Button("New group")  print("Create new group") 

我想这是因为我将Buttons 放在MenuButton 中,而它可能期待其他一些 SwiftUI 元素。我应该在 MenuButtons 中放置哪些元素来创建如下所示的正常外观的 macOS 菜单?

[更新] macOS Big Sur

我也在大苏尔尝试过。虽然背景渲染正确,但在 Big Sur 中,文本颜色现在混乱了。 ????

【问题讨论】:

您是否尝试过使用 MenuButton("+") 中的 .background() 而不是 Button? 我试过 MenuButton("+") Button("Hello") doNothing().background(.blue) 。你会建议什么? 这里一切正常。使用 Xcode 11.2.1 / macOS 10.15.2 测试。我什至尝试更改menuButtonStyle。除了强调色,你还改变了什么? 我尝试使用 Xcode 11.3.1 和 macOS 10.15.2。它对我有用。 @DamiaanDufaux 你有没有在(系统偏好设置>辅助功能>显示>降低透明度)上的“降低透明度”选项?我自己使用标准 AppKit API 遇到了这个渲染问题,然后在这里偶然发现了你的问题。禁用此选项后,渲染对我来说效果很好。你能确认一下吗? 【参考方案1】:

我想我通过配置ButtonStyle 并将其应用于MenuButton 通用结构找到了部分解决方案。但是请注意,.foregroundColor 的条件更改不会被个人的Button()Text() 继承。颜色也不对。

也许有人想对此进行改进。

struct DetectHover: ButtonStyle 
    @State private var hovering: Bool = false

    public func makeBody(configuration: DetectHover.Configuration) -> some View 
        configuration.label
            .foregroundColor(self.hovering ? Color.white : Color.primary)
            .background(self.hovering ? Color.blue : Color.clear)
            .onHover  hover in
                self.hovering = hover
            
    

MenuButton(label: Image(nsImage: NSImage(named: NSImage.actionTemplateName)!)) 

// Buttons

.buttonStyle(DetectHover())

【讨论】:

【参考方案2】:

我有一些几乎看起来正确的东西。我创建了一个自定义按钮,它在悬停时会改变外观。

我对 Swift 和 SwiftUI 都很陌生,所以下面的内容可能很笨拙。我欢迎任何改进。

struct HoverButton: View 
    var text = "Hover Button"
    var action = 
    @State private var hovering = false
    var body: some View 
        Button(text, action: action )
            .padding(.horizontal, 6)
            .padding(.vertical, 2)
            .buttonStyle(PlainButtonStyle())
            .frame(minWidth: 0, maxWidth: .infinity)
            .background(self.hovering ? Color(.selectedMenuItemColor) : Color(.clear))
            .onHover  hover in
                self.hovering = hover
            
    


//  Usage:
MenuButton("Test") 
    HoverButton(text: "Apple", action:  
        print("Apple")
    )
    HoverButton(text: "Banana", action:  
        print("Banana")
    )

.font(.system(size: 14, /* weight: .heavy, */ design: .default))
.menuButtonStyle(BorderlessButtonMenuButtonStyle())

创建自定义按钮的重点是访问Self,以便我可以更改其外观。但是,也有一些严重的缺点:

主要问题是按钮没有占据菜单主体的整个宽度。我不知道如何解决这个问题。

菜单按钮居中。我尝试将HStackSpacer() 一起使用,但没有帮助。

我不知道如何省略第一个参数名称作为真正的Button

【讨论】:

以上是关于如何在 SwiftUI 中以降低透明度为菜单项获取 AccentColor 背景?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 SwiftUI 中激活/停用菜单项

如何在 SwiftUI 中显示选定的菜单项?

SwiftUI:如何在 macOS 应用程序中实现编辑菜单

如何在swift / SwiftUI中为滑动手势设置菜单栏图标的操作

如何在 iOS 应用程序中以编程方式检测 SwiftUI 的使用情况

如何在 SwiftUI 中以形状显示文本?