如何实现带下拉菜单的工具栏按钮?NSSegmentedCell Chevron图标问题
嘿,我刚好对这种Mac上带下拉菜单的分段按钮实现熟得很,来帮你解决问题~
标准实现方案(匹配Mail应用的旗帜按钮逻辑)
Mail里的这种“点击图标执行默认动作,点击Chevron弹出菜单”的分段按钮,苹果其实有推荐的实现方式,核心是利用NSSegmentedCell的分段特性,结合菜单指示器的设置就能搞定,你遇到的Chevron不显示问题是因为漏开了一个关键属性。
具体实现步骤
1. 构建两段式分段控件
不管是用代码还是XIB/Storyboard,先创建一个NSSegmentedControl,设置分段数为2:
- 第一段:放你的旗帜图标,绑定标准动作(比如一键标记默认旗帜)
- 第二段:专门用来承载下拉菜单和Chevron,不需要设置图标或文字
用代码初始化的示例:
let flagSegment = NSSegmentedControl(segmentCount: 2, target: self, action: nil) // 第一段:设置旗帜图标+绑定默认动作 flagSegment.setImage(NSImage(named: NSImageNameFlag), forSegment: 0) flagSegment.setAction(#selector(triggerDefaultFlagAction(_:)), forSegment: 0)
2. 开启第二段的菜单指示器(关键!)
你之前给第二段绑定菜单后没显示Chevron,就是因为没开启showsMenuIndicator属性。只要打开这个开关,系统会自动帮你显示Chevron图标:
if let cell = flagSegment.cell as? NSSegmentedCell { // 给第二段开启菜单指示器 cell.setShowsMenuIndicator(true, forSegment: 1) // 绑定下拉菜单 let flagMenu = NSMenu() flagMenu.addItem(NSMenuItem(title: "标记红色", action: #selector(setRedFlag(_:)), keyEquivalent: "")) flagMenu.addItem(NSMenuItem(title: "标记橙色", action: #selector(setOrangeFlag(_:)), keyEquivalent: "")) flagMenu.addItem(NSMenuItem(title: "清除标记", action: #selector(clearFlag(_:)), keyEquivalent: "")) cell.setMenu(flagMenu, forSegment: 1) }
如果是用XIB/Storyboard配置更简单:选中分段控件的第二段,在Attributes Inspector里找到「Shows Menu Indicator」选项勾选,然后直接给该分段绑定菜单即可。
3. 实现动作逻辑
分别处理第一段的默认动作和菜单里的各个选项动作:
@objc private func triggerDefaultFlagAction(_ sender: NSSegmentedControl) { // 执行你的标准旗帜动作,比如切换默认标记状态 print("触发默认旗帜动作") } @objc private func setRedFlag(_ sender: NSMenuItem) { print("标记为红色旗帜") } @objc private func setOrangeFlag(_ sender: NSMenuItem) { print("标记为橙色旗帜") } @objc private func clearFlag(_ sender: NSMenuItem) { print("清除所有旗帜标记") }
额外优化建议
- 如果需要自定义Chevron的样式(比如和Mail完全一致的风格),可以重写
NSSegmentedCell的drawSegment:inFrame:withView:方法,手动绘制Chevron,但一般系统自带的指示器已经足够匹配系统UI风格了。 - 可以给第一段设置
isSpringLoaded属性,支持拖拽操作(像Mail里那样拖拽邮件到旗帜按钮快速标记)。
内容的提问来源于stack exchange,提问作者sbenitezb
相关产品推荐
相关产品推荐

