You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在SwiftUI的MenuBarExtra中添加滑块(非窗口样式)

在SwiftUI MenuBarExtra中实现NSMenu内嵌水平滑块效果

我想要实现原生NSMenu内嵌水平滑块的效果(如下所示),但使用SwiftUI的MenuBarExtra组件:

期望效果

当前我的代码如下:

MenuBarExtra("Menu Bar App", systemImage: "circle.fill") {    
    Text("Slider below")
    Slider(value: $sliderValue, in: 1...100)
    Text("Slider above")
}

运行后滑块无法正常显示,效果如下:

当前代码运行结果

添加.menuBarExtraStyle(.window)后滑块能正常显示,但这是独立窗口样式,并非我需要的下拉菜单效果:

window样式效果


解决方案:通过AppKit NSMenu自定义菜单内容

由于SwiftUI默认的MenuBarExtra下拉菜单基于NSMenu实现,而SwiftUI原生Slider无法在NSMenu中正常渲染,我们可以直接用AppKit API构建包含滑块的NSMenu,再关联到MenuBarExtra上。

1. 构建带滑块的自定义NSMenu

import SwiftUI
import AppKit

class CustomMenuBuilder {
    static func buildMenu(sliderValue: Binding<Double>) -> NSMenu {
        let menu = NSMenu(title: "")
        
        // 添加顶部文本项
        menu.addItem(NSMenuItem(title: "Slider below", action: nil, keyEquivalent: ""))
        
        // 创建滑块菜单项
        let sliderItem = NSMenuItem()
        let slider = NSSlider(frame: NSRect(x: 0, y: 0, width: 200, height: 25))
        slider.minValue = 1
        slider.maxValue = 100
        slider.floatValue = Float(sliderValue.wrappedValue)
        slider.target = SliderTarget(value: sliderValue)
        slider.action = #selector(SliderTarget.updateValue(_:))
        sliderItem.view = slider
        menu.addItem(sliderItem)
        
        // 添加底部文本项
        menu.addItem(NSMenuItem(title: "Slider above", action: nil, keyEquivalent: ""))
        
        return menu
    }
}

// 处理滑块值更新的绑定对象
class SliderTarget: NSObject {
    private let value: Binding<Double>
    
    init(value: Binding<Double>) {
        self.value = value
        super.init()
    }
    
    @objc func updateValue(_ sender: NSSlider) {
        value.wrappedValue = Double(sender.floatValue)
    }
}

2. 在MenuBarExtra中关联自定义菜单

struct ContentView: View {
    @State private var sliderValue = 50.0
    
    var body: some View {
        MenuBarExtra("Menu Bar App", systemImage: "circle.fill") {
            // 保留空内容,将用自定义NSMenu替换
        }
        .menuBarExtraStyle(.menu)
        .onAppear {
            guard let statusItem = NSApp.statusItems.first else { return }
            statusItem.menu = CustomMenuBuilder.buildMenu(sliderValue: $sliderValue)
        }
    }
}

效果说明

  • 该方案完全复用原生NSMenu的交互逻辑,滑块在下拉菜单中可正常拖动,和目标效果一致。
  • SliderTarget类负责将AppKit滑块的数值变化同步到SwiftUI的@State变量,实现双向数据绑定。
  • 确保使用.menu样式(默认即为该样式),避免切换到独立窗口模式。

内容的提问来源于stack exchange,提问作者jxxe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 13:20:34